正则表达式匹配数字范围或数字列表

6
我需要一个正则表达式来匹配数字列表,另一个用来匹配数字范围(两种情况下都不应失败)。范围应由一个数字、一个破折号和另一个数字(N-N)组成,而列表应由逗号分隔的数字(N,N,N)组成。以下是一些示例。
区间:
- 1-5 - 10-20 - 3-3
数字列表:
- 1,2,3 - 10,11,12,13 - 5
'1-10' => OK
Whateverelse => NOK (e.g. '1-10 11-20')

列表:

'1,2,3' => OK
Whateverelse => NOK

以下是我的两个正则表达式:

  1. [0-9]+[\-][0-9]+
  2. ([0-9]+,?)+

...但我在处理它们时遇到了一些问题,例如:

当对 '1-10' 进行匹配时,正则表达式 2 匹配到了 1,但实际上该字符串并没有列表,所以它不应该匹配任何内容。

然后,当对 '1-10 11-14' 进行匹配时,正则表达式 1 匹配到了 1-10,但实际上该字符串不仅包含范围,还包含其他内容,所以它也不应该匹配任何内容。

我是否漏掉了什么?谢谢。


“1,2,4”可以吗?您需要数字按顺序排列吗? - unlimit
只是一个小提示,你可以使用这个网站:http://regexpal.com/ 来测试正则表达式。 - string.Empty
当你想要高级功能时,它也取决于你使用的正则表达式的版本。Perl 有一套功能,Awk 有另一套。UNIX 风格的程序深度依赖于所使用的操作系统。 - Gilbert
正则表达式用于匹配模式,而不是检查数字值。使用正则表达式找到一个可能的字符串,然后在您所使用的主机语言(如PHP等)中检查其数值。 - Andy Lester
5个回答

5

试试这个:

^((\d+-(\*|\d+))|((\*|\d+)-\d+)|((\d)(,\d)+))$

测试结果:

1-10         OK
1,2,3        OK
1-*          OK
*-10         OK
1,2,3 1-10   NOK
1,2,3 2,3,4  NOK
*-*          NOK

正则表达式的可视化:

正则表达式的可视化

编辑:根据OP的评论添加了通配符*


这个可以用于我想要做的事情... 我刚刚添加了通配符支持,以允许诸如“3-*”或“*-10”之类的表达式:^(([\\d]+-[\\d]+)|((\d)(,\d)+))$;问题是这个正则表达式也匹配了像"*-*"这样的表达式(通配符只能在右侧或左侧,不能同时出现在两边)。 - j3d
我假设您还想匹配 1-*, *-1 但不匹配 *-*?请查看我的更新答案。 - unlimit

2

这个有点不同,它是用于Procurve交换机上的端口。
^(((\d+)|(\d+-\d+))(,((\d+)|(\d+-\d+)))*)$
它是用perl编写的。

1                    OK
2                    OK
3                    OK
1-4                  OK
0-A                  NOK
83-91                OK
14,15,16             OK
14,20-25,91          OK
a,b-c,5,5,5          NOK
this-is,5,7,9        NOK
9,8,1-2,1-7          OK

我没有包括上面的 * 符号。而你 (@unlimit) 用了什么工具制作出那个精美的图表呢?

-E


我认为将 (\d+-\d+) 移动到 (\d+) 之前可以使模式与您的测试结果正确匹配: (((\d+-\d+)|(\d+))(,((\d+-\d+)|(\d+)))*) - ThanhLD
我刚刚测试了一下(再次),它按照预期工作。也就是说,它返回响应中列出的结果。移动表达式会有什么变化? - Erik Bennett
我在 https://regexr.com 上测试了你的正则表达式,它不能匹配所有测试样例。 - ThanhLD
它能与Perl一起使用吗?除非我犯了一个剪切和粘贴错误,否则这些都是真实测试的结果。 - Erik Bennett

1

首先,您应该使用锚点来确保正则表达式匹配整个字符串而不仅仅是子字符串:

^[0-9]+-[0-9]+$

然后,在第二个正则表达式中,逗号是可选的。请尝试使用以下内容:
^([0-9]+,)+[0-9]+$

0
最简单的解决方案是在第二个结果周围添加额外的括号:
(([0-9]+,?)+)

正如其他人所指出的,如果您正在输入文本并且这是整个输入,则应该以^$开头和结尾:

^(([0-9]+,?)+)$

如果您正在搜索文本内容以提取这些值,那么您将不需要那个。

括号表示匹配组。如果您在开头添加(?:而不是(,也可以将内部括号标记为“非捕获组”。 这将使您得到:

((?:[0-9]+,?)+)

这意味着你只捕获到了你想要的值。你也可以忽略第二个捕获。

0

我需要匹配逗号分隔的整数列表,比如1,2,3,4,同时还可以指定范围,比如100-255和组合,比如1011,1100-1300,1111,1919-9999,2111。基本上是OP请求及其组合。

为此,我使用了在Regex101.com上测试的以下正则表达式:

^\d+((\,|-)\d+)*$

您可以将其视为:

  1. 从字符串开头
  2. 期望1个或多个数字,然后要么...
  3. 一个逗号和1个或多个数字,要么...
  4. 一个连字符和1个或多个数字
  5. 重复执行(3)和(4)零次或多次
  6. 直到字符串结尾

这允许所有以下内容都是有效的:

2011,2100-2300
2011,2013
1014-2024
999
1011,1100-1300,1111,1919-9999,2111

注意:如果用于多行输入,则应包括全局和多行正则表达式选项/gm
缺点是像100-100-100这样的内容仍然有效,即使其他类型的更改将确保没有匹配。不确定进一步解决它的复杂性,但对我的需求已经足够好了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接