正则表达式允许数字,破折号,逗号

时间:2019-05-17 07:14:26

标签: c# regex

我想知道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);

5 个答案:

答案 0 :(得分:7)

您可以使用此正则表达式,

^(?:[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

答案 1 :(得分:6)

您可以尝试

   ^[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}
  • 如果您想禁止前导零(01212必须失败时必须0失败),请将每个[0-9]{1,3}片段更改为(?:0|[1-9][0-9]{0,2})

答案 2 :(得分: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

答案 3 :(得分:1)

这是我尝试使用\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)

答案 4 :(得分:1)

这里似乎有很多异常复杂的答案,所以这是我的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))

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

更新

@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