正则表达式 - 负向先行断言

4

我希望你能够为我提供建议,我正尝试使用Perl的负向前瞻正则表达式来排除目标字符串中的某些内容。

我想要获取不包含-sm、-sp或-sa的字符串。

正则表达式:

hostname .+-(?!sm|sp|sa).+

输入

hostname 9amnbb-rp01c
hostname 9tlsys-eng-vm-r04-ra01c
hostname 9tlsys-eng-vm-r04-sa01c
hostname 9amnbb-sa01
hostname 9amnbb-aaa-sa01c

期望的输出结果:

hostname 9amnbb-rp01c              - SELECTED
hostname 9tlsys-eng-vm-r04-ra01c   - SELECTED 
hostname 9tlsys-eng-vm-r04-sa01c
hostname 9amnbb-sa01
hostname 9amnbb-aaa-sa01c

然而,我得到了下面的实际输出:
hostname 9amnbb-rp01c              - SELECTED
hostname 9tlsys-eng-vm-r04-ra01c   - SELECTED
hostname 9tlsys-eng-vm-r04-sa01c   - SELECTED
hostname 9amnbb-sa01
hostname 9amnbb-aaa-sa01c          - SELECTED

请帮助我。

p.s.: 我使用Regex Coach来可视化我的结果。

2个回答

4

.+-移动到前瞻中:

hostname (?!.+-(?:sm|sp|sa)).+

Rubular: http://www.rubular.com/r/OuSwOLHhEy

您当前的表达式无法正常工作,因为当 .+- 在前瞻之外时,它可以回溯直到前瞻不再导致正则表达式失败。例如,在字符串 hostname 9amnbb-aaa-sa01c 和正则表达式 hostname .+-(?!sm|sp|sa).+ 中,第一个 .+ 将匹配 9amnbb,前瞻会将 aa 视为下两个字符并继续,而第二个 .+ 将匹配 aaa-sa01c

我的当前正则表达式的另一种替代方法是:

hostname .+-(?!sm|sp|sa)[^-]+?$

这将防止回溯,因为在预查后面不会出现任何-,使用非贪婪的?以便在多行全局模式下正确工作。


这需要负向先行断言吗? - Rudie
1
@Rudie:可能不会,但是没有前瞻的表达式会更加复杂。 - Wormbo
第二个正则表达式 'hostname .+-(?!sm|sp|sa)[^-]+?$' 匹配了 'hostname a-b-sm-c',但它不应该这样。 - Dave F

1
以下内容通过了您的测试用例:
hostname [^-]+(-(?!sm|sp|sa)[^-]+)+$

我认为这比F.J.的回答更容易阅读。

回答Rudy:问题被提出为排除情况的情况。这似乎很适合负向先行搜索。 :)


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