【问题标题】:RegEx allowing digit, dash, comma正则表达式允许数字、破折号、逗号
【发布时间】:2019-05-17 07:14:26
【问题描述】:

我想知道 c# 的正则表达式是否满足以下模式:

  • 只允许数字、逗号和数字
  • 必须以数字开头和结尾
  • 数字范围是0到999
  • 数字(例如 1,2,3)或范围(例如 1-3, 2-5)用 ',' 分隔
  • 两个 ',' 之间必须是数字或范围
  • '-' 必须以数字开头和结尾
  • ',' 后只允许 0-1 个空格

示例:

1-100,134,200 --> PASS. Maximum range of numbers 0-999
1,18,100      --> PASS
1, 18, 100    --> PASS. Allow 0-1 white space after ',' 
1,  18,100    --> FAIL. Due to more than 1 white space after ','
1-,18,100     --> FAIL. Due to no digit after '-'
-2,18,100     --> FAIL. Due to no digit before '-'
1,,18,100     --> FAIL. Due to no digit between ','
1, ,18,100    --> FAIL. Due to no digit between ','
,2,18,100     --> FAIL. Due to no digit before ','
1,18,100,     --> FAIL. Due to no digit after ','

我尝试使用以下代码,但它总是返回一个真实的结果:

string pattern = @"[0-9]+(?:-[0-9]+)?(,[0-9]+(?:-[0-9]+)?)*";
string test = @"1-5,13,238,-a";
bool result = Regex.IsMatch(test, pattern);

【问题讨论】:

  • 在使用正则表达式时,我总是发现 rubular.com 非常有用,检查一下,它会定义。帮助你。
  • 当我使用 regexr.com 验证表达式时它可以工作。但是,当我使用 c# 代码时,它一直返回“true”。除此之外,我也不确定如何限制数字并在其中添加空格表达式,因为我从其他地方复制了表达式。
  • 这样的事情可能会起作用:^(?:\d+(?:-\d+)?,?\s?)+$(编辑:结尾有逗号时不起作用)
  • @adiga 您的表达式适用于大多数情况,除了末尾的逗号(您已经指出)和数字范围(0 到 999)。我可以简单地使用 c# 代码进行字符串检查,以检查是否以逗号结尾。谁能知道如何修改 adiga 的表达式以支持范围?
  • aah 没有看到 999 位。将\d 替换为\d{1,3}

标签: c# regex


【解决方案1】:

你可以使用这个正则表达式,

^(?:[1-9]\d\d|[1-9]?\d)(?:-(?:[1-9]\d\d|[1-9]?\d))?(?:,\s?(?:[1-9]\d\d|[1-9]?\d)(?:-(?:[1-9]\d\d|[1-9]?\d))?)*$

说明:

  • ^ - 字符串开始
  • (?:[1-9]\d\d|[1-9]?\d) - 代表一个数字 0999 并且不允许像 005 这样带有前导零的数字
  • (?:-(?:[1-9]\d\d|[1-9]?\d))? - 可选地还允许用连字符分隔的数字 - 与第一个正则表达式数字一起,它支持像 2222-33 等数字。
  • (?:,\s?(?:[1-9]\d\d|[1-9]?\d)(?:-(?:[1-9]\d\d|[1-9]?\d))?)* - 这部分只支持逗号分隔,可选后跟一个空格,整个空格零次或多次
  • $ - 字符串结束

我本可以使用 \d{1,3} 来表示从 0999 的数字,但这将允许像 004 这样的数字,这似乎不允许查看您的示例数据。但是,如果确实允许像 00404 这样的数字是可以的,那么您可以在我的正则表达式中将 [1-9]\d\d|[1-9]?\d 替换为 \d{1,3} 以使其变得简单。

Regex Demo

【讨论】:

  • 谢谢。你的表达有效。你还帮我把前面的零去掉。
  • @jpmc26:嗯,就像尝试阅读/理解一种人们不知道/不理解的语言一样。对于任何了解正则表达式基础知识的人来说,我的正则表达式应该是微不足道的。另外,我已经在我的正则表达式中添加了解释,这应该使它易于理解。如果你能想出一个比我更简单、更易读的正则表达式,我会认为你是一个真正的正则表达式大师,并为你脱帽致敬。
  • @jpmc26:环顾四周?你在哪里看到的?我以为你说你非常了解正则表达式。你能把你看到的东西显示为环视吗?
  • @jpmc26:老实说,我认为你甚至没有正确理解我的正则表达式。否则,您也应该向其他答案提出这个问题,他们的正则表达式与我的相同,除了他们的正则表达式允许数字中的前导零,因为他们使用 \d{1,3} 而不是 [1-9]\d\d|[1-9]?\d 否则结构是相同的。您没有向他们提出同样问题的原因告诉我您不太了解正则表达式,因为您无法解码我的正则表达式。如果以更简单的形式编写,我的正则表达式可以写为X(-X)?(,X(-X)?)*,其中X = [1-9]\d\d|[1-9]?\d。你能看出它有多简单吗?
  • @jpmc26:为什么正则表达式不能很好地解决这个问题?即使是这样,OP 除了使用正则表达式之外别无选择呢?另外,如果您认为编码会是更好的解决方案,那么我不同意。如果您对正则表达式足够了解,那么与我看到的其他正则表达式相比,这个正则表达式算不了什么。按照您的理念,具有良好正则表达式能力的人是无用的并且不需要,因为如果正则表达式变得复杂,他们需要转向编码解决方案。抱歉,我不同意。
【解决方案2】:

你可以试试

   ^[0-9]{1,3}(?:\-[0-9]{1,3})?(?:,\s?[0-9]{1,3}(?:\-[0-9]{1,3})?)*$

模式在哪里

   ^                             String start
   0*[0-9]{1,3}                  1 to 3 digits
   (?:\-[0-9]{1,3})?             Possible minus (-) followed 1 to 3 digits (e.g. -456)
   ?:,\s?                        Comma and at most one whitespace  
   [0-9]{1,3}(?:\-[0-9]{1,3})?)* 1 to 3 digits or range repeated zero or more times
   $                             End of string        

演示:

  string pattern = 
    @"^[0-9]{1,3}(?:\-[0-9]{1,3})?(?:,\s?[0-9]{1,3}(?:\-[0-9]{1,3})?)*$";

  string[] tests = new string[] {
    "123",
    "1234",
    "123-456",
    "123,456",
    "1-100,134,200",
    "1,18,100",
    "1, 18, 100",
    "1,  18,100",
    "1-,18,100",
    "-2,18,100",
    "1,,18,100",
    "1, ,18,100",
    ",2,18,100",
    "1,18,100,",
  };

  string[] results = tests
    .Select(test => $"{test,-20} --> {(Regex.IsMatch(test, pattern) ? "PASS" : "FAIL")}")
    .ToArray();

  string report = string.Join(Environment.NewLine, results);

  Console.Write(report);

结果:

123                  --> PASS
1234                 --> FAIL 
123-456              --> PASS
123,456              --> PASS
1-100,134,200        --> PASS
1,18,100             --> PASS
1, 18, 100           --> PASS
1,  18,100           --> FAIL
1-,18,100            --> FAIL
-2,18,100            --> FAIL
1,,18,100            --> FAIL
1, ,18,100           --> FAIL
,2,18,100            --> FAIL
1,18,100,            --> FAIL

编辑:

  • 如果您想允许任意多个前导零(例如 000123 实际上是 123),请将每个 [0-9]{1,3} 片段更改为 0*[0-9]{1,3}
  • 如果你想禁止前导零(012 必须失败,当120 必须)通过时,将每个[0-9]{1,3} 片段更改为(?:0|[1-9][0-9]{0,2})

【讨论】:

  • 你的表达很有效。不幸的是,我只能检查 post.as 答案。尽管如此,我赞成你的回答。
【解决方案3】:

尝试以下模式:^(?:\d{1,3}-\d{1,3}|\d{1,3})(?:, ?(?:\d{1,3}-\d{1,3}|\d{1,3}))*$

解释:

^ - 匹配字符串的开头

(?:...) - 非捕获组

\d{1,3} - 匹配 1 到 3 位数字

- - 从字面上匹配破折号

| - 交替,匹配右边的内容 (\d{1,3}) 或左边的内容 (\d{1,3}-\d{1,3})

, ? - 匹配 , 后跟零个或一个空格

* - 匹配 (?:, ?(?:\d{1,3}-\d{1,3}|\d{1,3})) 零次或多次

$ - 匹配字符串的结尾

Demo

【讨论】:

  • 你的表达很有效。不幸的是,我只能检查 post.as 答案。尽管如此,我赞成你的回答。
【解决方案4】:

这是我尝试使用\b 一个单词边界,也许它对您的需求足够准确。

^(?:\d{1,3}(?:-\d{1,3})?(?:, ?)?\b)+$

this demo at regex 101 中使用它(右侧的说明)。

如果您需要不带前导零的 0-999 check,请替换 \d{1,3} with (?:[1-9]\d\d?|\d)

【讨论】:

    【解决方案5】:

    这里似乎有很多异常复杂的答案,所以这是我的 2 美分:

    ^([1-9]\d{0,2}|0)((\-|, ?)([1-9]\d{0,2}|0))*$
    

    我认为这个答案“不那么复杂”,不是因为它更短(这里不是最短的),而是因为它没有使用“复杂”的正则表达式行为。
    它仅使用常见的匹配组()、常见的量词(*{,}?)和常见的匹配符号,例如\d[1-9]

    没有环视、前瞻、后视、非捕获组、反向引用或任何其他“复杂”正则表达式行为

    解释:

    ^([1-9]\d{0,2}|0)((\-|, ?)([1-9]\d{0,2}|0))*$
    ^                                               Start of string
     (                                              Start of capture group:
      [1-9]\d{0,2}                                    A non-zero digit followed by 0 to 2 digits.
                                                        Matches any 1-999 number without leading zeroes
                  |                                   OR
                   0                                  Just a zero
                    )                               End of capture group
                     (                             Start of capture group:
                      (                              Start of capture group:
                       \-                              Dash
                         |                             OR
                          , ?                          Comma Followed by 1 or 0 spaces
                             )                       End of capture group
                              ([1-9]\d{0,2}|0)       Same 0-999 capture group as earlier
                                              )     End of capture group
                                               *    Previous capture group matched 0 or more times
                                                $   End of string
    

    简而言之,如果您想要稍微不那么技术性的描述:

    Number 是一个介于 0-999 之间的数字
    (用正则表达式表示:([1-9]\d{0,2}|0)

    Separator 是逗号加 0 或 1 个空格,或者是破折号
    (用正则表达式表示:(\-|, ?)

    Group 是一个分隔符,后跟一个数字
    (用正则表达式表示:((\-|, ?)([1-9]\d{0,2}|0))

    此正则表达式匹配:
    一个数字,后跟零个或多个

    更新

    cmets 中的@bobblebubble 指出这将允许,例如1-2-3,这可能是不允许的,因为- 旨在指定一个范围。

    以下是修复此问题的修改:

    ^(([1-9]\d{0,2}|0)(-([1-9]\d{0,2}|0))?)(, ?(([1-9]\d{0,2}|0)(-([1-9]\d{0,2}|0))?))*$
    

    这比原来的要长得多,所以在 C# 中我会这样拆分它:

    // This pattern will match a single 0-999 number, or a range
    string numPatt = "(([1-9]\d{0,2}|0)(-([1-9]\d{0,2}|0))?)";
    // This pattern will match a csv of numPatts
    string pattern = $"^{numPatt}(, ?{numPatt})*$";
    

    然后根据需要使用pattern

    【讨论】:

    • 这很有趣,但它matches eg 1-2-3 我不知道它是否被允许(范围)。但是很好的答案和解释以及一个选项!
    • @bobblebubble 好点,更新不难,很快就会更新
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多