有没有办法缩短这个正则表达式?

时间:2013-09-11 22:27:51

标签: ruby regex

我希望以A0123456E0123456IN:A0123456Q等格式匹配字符串。我最初制作此正则表达式

^(IN:)?[AE][0-9]{7}Q?$

但最终匹配的IN:E012346没有Q。所以我创建了这个正则表达式

(^IN:[AE][0-9]{7}Q$)|(^[AE][0-9]{7}$)

有没有办法缩短这个正则表达式,如果它们存在则需要IN:Q,但如果两者都不存在则不需要?

编辑:正则表达式将在Ruby中使用。

编辑2:我更改了正则表达式以反映我匹配错误的字符串,因为它仍然匹配IN:A0123456

编辑3:下面的两个答案都是有效的,但由于我使用Ruby 2.0并且更喜欢正则表达式,我可以使用以防我更改应用程序并且不想使用子表达式调用的Ruby风格,我选择接受matt的答案。

2 个答案:

答案 0 :(得分:5)

第二个正则表达式有问题:

^(IN:[AE][0-9]{7}Q)|([AE][0-9]{7})$

|的优先级低于连接,因此正则表达式将被解析为:

^(IN:[AE][0-9]{7}Q)        # Starts with (IN:[AE][0-9]{7}Q)
|                          # OR
([AE][0-9]{7})$            # Ends with ([AE][0-9]{7})

要解决此问题,只需使用非捕获组

^(?:(IN:[AE][0-9]{7}Q)|([AE][0-9]{7}))$

确保输入字符串与任何格式匹配,而不仅仅是以某种格式开头或结尾(这显然不正确)。


关于缩短正则表达式,如果您愿意,可以将[0-9]替换为\d,但它可以正常使用。

我认为在Ruby的默认支持级别内没有任何其他方法可以缩短正则表达式。

子程序调用

只是为了您的信息,在Perl / PCRE中,您可以使用 子例程调用 来缩短它:

^(?:([AE][0-9]{7})|(IN:(?1)Q))$

(?1)是指第一个捕获组定义的模式,即[AE][0-9]{7}。正则表达式实际上是相同的,只是看起来更短。输入IN:E0123463Q的{​​{3}}显示第2组捕获的整个文本(并且没有为第1组捕获的文本)。


在Ruby中,存在This demo 子表达式调用 ,语法略有不同。 Ruby使用\g<name>\g<number>来引用我们想要重用其模式的捕获组:

^(?:([AE][0-9]{7})|(IN:\g<1>Q))$

Ruby 1.9.7下的similar concept,对于输入IN:E0123463Q,返回E0123463作为第1组匹配,IN:E0123463Q作为第2组匹配。

Ruby的(1.9.7)实现似乎记录了组1的捕获文本,即使组1没有直接参与匹配。在PCRE中,子程序调用不会捕获文本。

条件正则表达式

还有 条件正则表达式 ,可让您检查某个捕获组是否与某些内容匹配。您可以查看test case here on rubular以获取更多信息。

答案 1 :(得分:3)

如果您使用的是Ruby 2.0,则可以使用if-then-else conditional match(在Ruby文档中未记录,但确实存在):

/^(IN:)?[AE][0-9]{7}(?(1)Q|)$/

条件部分为(?(1)Q|),表示如果组号1匹配,则匹配Q,否则不匹配。由于第1组是(IN:),因此可以实现您的目标。