尝试构建一个正则表达式以检查模式。

3

a) 以数字开头和结尾
b) 连字符应该以数字开头和结尾
c) 逗号应该以数字开头和结尾
d) 数字范围应该在1-31之间

[编辑:需要将此规则添加到正则表达式中,谢谢Ed-Heal!]
e) 如果数字以连字符(-)开头,则不能以除逗号以外的任何其他字符结尾,并遵循上述所有规则。
例如,2-2,1或2,2-1是有效的,而1-1-1-1是无效的

例如:
a) 1-5,5,15-29
b) 1,28,1-31,15
c) 15,25,3 [编辑:将56替换为3,感谢Brian指出!]
d) 1-24,5-6,2-9

尝试了这个但即使字符串以逗号开头也会通过:

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

1
在(c)中的最终数字大于31,是示例或描述错误吗? - tripleee
也许你只需说你有一些东西的列表(分隔符为逗号),其中一个东西是从1到31的范围(分隔符为破折号)或者一个数字。 - Ludovic Kuty
你使用的编程语言或正则表达式风格是什么? - Ludovic Kuty
1
你表述限制条件(e)的方式似乎排除了5这个数字,因为它以相同的字符开头和结尾。我猜你真正的意思是允许一个由逗号分隔的数字或数字对列表,并在它们之间用连字符连接。 - tripleee
7个回答

3

这个呢?它至少会检查规则a、b和c,但不会检查规则d。

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

如果您需要确保所有数字都在1-31范围内,则表达式会变得非常丑陋:

/^([1-9]|[12][0-9]|3[01])(-([1-9]|[12][0-9]|3[01]))?(,([1-9]|[12][0-9]|3[01])(-([1-9]|[12][0-9]|3[01]))?)*$/

请注意,您的示例c包含一个数字56,它不在1-31的范围内,因此它不能通过第二个表达式。


满足所有要求且不过度的+1 ;) 它适用于任何版本,这很好,因为OP没有指定。 (只需按照指示将“/”替换为“”即可。) - Alan Moore
+1。但是,如果您使用了自由间隔模式,并添加了许多注释和缩进,那么这个“丑陋”的表达式将变得非常漂亮! - ridgerunner

0

这是我的工作:

数字:

0|([1-9][0-9]*) 将此表达式称为 A 请注意,此表达式将零视为特殊情况,并防止以零开头的数字,例如 0000001234

数字或范围:

A|(A-A) 将此表达式称为 B(即(0|([1-9][0-9]*))|((0|([1-9][0-9]*))-(0|([1-9][0-9]*)))

逗号运算符

B(,B)*

将这些组合起来就可以了:

((0|([1-9][0-9]*))|((0|([1-9][0-9]*))-(0|([1-9][0-9]*))))(,((0|([1-9][0-9]*))|((0|([1-9][0-9]*))-(0|([1-9][0-9]*)))))*

您可以使用\d代替[0-9]进行缩写。


0

使用与我之前答案相同的逻辑,但限制范围

A 变成 [1-9]\d|3[01] B 变成 ([1-9]\d|3[01])|(([1-9]\d|3[01])-([1-9]\d|3[01]))

总体表达式

(([12]\d|3[01])|(([12]\d|3[01])-([12]\d|3[01])))(,(([12]\d|3[01])|(([12]\d|3[01])-([12]\d|3[01]))))*


我认为你的括号不平衡。 - Brian Rogers
当然,应该提到这个正则表达式无法处理第一个数字大于第二个数字的范围 = 那将是一个非常复杂的表达式!(留给读者自己实现) - Ed Heal
幸运的是,OP没有将从低到高的范围表达式列为要求。然而,您仍然没有正确限制数字; [1-9]\d|3[01] 可匹配 10 到 99 范围内的数字,而不是 1 到 31。 - Alan Moore
@alan - 你说得对 - 我下班了,大脑也停机了。我会修复的。 - Ed Heal
@Ed Heal:那个单数字呢? - Brian Rogers

0
我提出以下正则表达式:
(?<number>[1-9]|[12]\d|3[01]){0}(?<thing>\g<number>-\g<number>|\g<number>){0}^(\g<thing>,)*\g<thing>$

看起来很糟糕,但实际上并不是 :) 实际上,构造 (?<name>...){0} 允许我们定义一个命名的正则表达式,并说它不匹配其定义的位置。因此,我定义了一个数字模式称为 number 和一个我称之为事物的模式,即范围或数字,称为 thing。接下来,我知道您的表达式是这些事物的序列,因此我使用命名的正则表达式 thing 用构造 \g<thing> 来构建它。它给出了 (\g<thing>,)*\g<thing>。这很容易阅读和理解。如果您允许在正则表达式中将空格视为不重要,则甚至可以像这样缩进:

(?<number>[1-9]|[12]\d|3[01]){0}
(?<thing>\g<number>-\g<number>|\g<number>){0}
^(\g<thing>,)*\g<thing>$/

我已经使用Ruby 1.9.2进行了测试。你的正则表达式引擎应该支持命名组,以允许这种清晰度。

irb(main):001:0> s1 = '1-5,5,15-29'
=> "1-5,5,15-29"
irb(main):002:0> s2 = '1,28,1-31,15'
=> "1,28,1-31,15"
irb(main):003:0> s3 = '15,25,3'
=> "15,25,3"
irb(main):004:0> s4 = '1-24,5-6,2-9'
=> "1-24,5-6,2-9"
irb(main):005:0> r = /(?<number>[1-9]|[12]\d|3[01]){0}(?<thing>\g<number>-\g<number>|\g<number>){0}^(\g<thing>,)*\g<thing>$/
=> /(?<number>[1-9]|[12]\d|3[01]){0}(?<thing>\g<number>-\g<number>|\g<number>){0}^(\g<thing>,)*\g<thing>$/
irb(main):006:0> s1.match(r)
=> #<MatchData "1-5,5,15-29" number:"29" thing:"15-29">
irb(main):007:0> s2.match(r)
=> #<MatchData "1,28,1-31,15" number:"15" thing:"15">
irb(main):008:0> s3.match(r)
=> #<MatchData "15,25,3" number:"3" thing:"3">
irb(main):009:0> s4.match(r)
=> #<MatchData "1-24,5-6,2-9" number:"9" thing:"2-9">
irb(main):010:0> '1-1-1-1'.match(r)
=> nil

(?<number>[1-9]|[12]\d|3[01]) 应该写成 (?<number>3[01]|[12]\d|[1-9]) - Ludovic Kuty

0

这个主题的最佳正则表达式可能是:

^(?'int'[1-2]?[1-9]|3[01])((,\g'int')|(-\g'int'(?=$|,)))*$

演示


0

试一下这个

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

演示


虽然可以使用“正向后瞻断言(?<=)”来完成,但我真的不知道该怎么做。 - xkeshav
\d+太宽泛了。数字范围在1到31之间。 - Ludovic Kuty

0
其他方法并没有限制允许的数字范围。这种方法只允许1到31,似乎比一些人想出来的庞然大物更简单...
^([12][0-9]?|3[01]?|[4-9])([-,]([12][0-9]?|3[01]?|[4-9]))*$

这里没有检查合理的范围; 添加检查会使表达式变得更加复杂。最终你可能最好使用一个更简单的正则表达式,并在代码中实现健全性检查。


1
关于范围为1-31的好点(我没有考虑到),你的表达方式允许 1-1-1-1-1。 - Ed Heal

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