如何在一行中编写包含`abc`或`bcd`而不是`diy`的正则表达式

时间:2012-03-28 02:40:45

标签: regex perl shell

我只是写下:

if $_ =~ /abc|bcd/ && $_ !~ /diy/

如何在一个正则表达式中编写它。 perlgrep都可以。感谢。

4 个答案:

答案 0 :(得分:3)

另一个答案中建议的前瞻/后方不适用于此问题。要使用lookbehind,你需要可变长度的lookbehind,perl不支持。

/^(?!.*?diy).*?(?:abc|bcd)/s

另一种方法:

/^(?:(?!diy).)*(?:abc|bcd(?!iy))(?:(?!diy).)*\z/s

在任何一种情况下,将bc从|中分解出来可以产生更有效的正则表达式。

答案 1 :(得分:2)

否定一系列字符通常是正则表达式中的一种痛苦。你必须使用预见断言。

如果您正在测试连续序列,您可以尝试使用前瞻和后视,例如(?<!diy)(abc|bcd)(?!diy),但这可能是模棱两可的。

我会像你一样离开测试,只丢失默认变量:

if /(abc|bcd)/ and not /diy/

清除干净。 :)

答案 2 :(得分:2)

当然,正则表达式可以使用一些先行断言

$i =~ /^(?=.*(?:abc|bcd))(?!.*diy)/
如果您想要其中一个部分

(?=.*(?:abc|bcd))将成立 如果你不想要的字符串在那里,

(?!.*diy)将会失败

但我认为你的解决方案更清晰。

答案 3 :(得分:1)

$ echo 'now I know my abcs' | txr -c '@/.*(abc|bcd).*&~.*diy.*/' -

$ echo 'no match' | txr -c '@/.*(abc|bcd).*&~.*diy.*/' -
false

$ echo 'Kaz wanted better regex, so he did the diy thing, starting from abc' | txr -c '@/.*(abc|bcd).*&~.*diy.*/' -
false

false伴随着终止状态失败,并表示不匹配。没有输出意味着匹配。

我们使用.*,因为匹配是锚定的。 @/RE/本身在一行上意味着该行必须与正则表达式匹配;也就是说,当我们将该线路送到正则表达式机器时,从开始到结束,机器都处于接受状态。

当你有这样的正则表达式时,在正则表达式中使用搜索语义是不好的。即如果foo实际上意味着.*(foo).*(在文本中的任何位置匹配foo),那对于foo&~bar来说效果不佳,因为.*(foo&~bar).*并不意味着相同作为.*foo.*&~.*bar.*的事情。前者表示“匹配任何具有匹配foo&~bar的子字符串的字符串。”但这是一场不可能的比赛;没有字符串可以同时为foobar。这是一个空的十字路口。但后者意味着“匹配其中包含foo的字符串,但在任何地方都不包含bar。”现在你正在做生意。