Lookbehind不能按预期工作

时间:2014-02-02 10:01:49

标签: regex perl

我正在努力了解这种背后 我尝试的这个例子不像我预期的那样工作。我想尝试形成一个匹配John而不是John.的正则表达式 以下内容:

$ perl -e '  
my $var = "John.";  
if( $var =~ m/J*/) {  
print "Matches!\n";  
}  
'  
Matches!  

当然与.匹配并包括$ perl -e ' my $var = "John."; if( $var =~ m/J*(?<![.])/) { print "Matches!\n"; } ' Matches! 。问题如下:

John.

对于后者,我预计正则表达式将匹配my $var = "John. "; 消费&gt;。&lt; (期间)
然后在下一个位置,它会向后看,并意识到它消耗了一段时间(。)并拒绝匹配 我的理解错了吗?我在这里搞砸了什么?

更新
John

的结果也相同

更新2
我的问题不在于如何仅匹配John.而不是{{1}} 但要理解外观是如何工作的,以及它是否应该在这种情况下起作用。

2 个答案:

答案 0 :(得分:4)

*是量化运算符,而不是占位符。因此A*表示零个或多个A个字符。没有任何进一步的背景,这总是匹配,例如, "foo" =~ /J*/是真的。

你打算写的是/J.*/,你做了你实际描述过的事情。

现在让我们来看看当我们"John." =~ /(J.*(?<![.]))/时会发生什么:

  • 正则表达式引擎会看到匹配的J
  • 下一个模式为.*,与ohn.匹配。
  • 接下来测试断言(?<![.]),但失败了。
  • 因此正则表达式引擎回溯
  • 我们再次尝试.*,但这次只匹配ohn
  • 接下来测试断言(?<![.]),即成功。

在上面的正则表达式中,我将模式包含在一个捕获组中,我们现在可以读出它:

$ perl -E'"John." =~ /(J.*(?<![.]))/ and say "<$1>" or say "No match"'
<John>

使用字符类而不是断言和.*量化通常更有效,这样我们就可以避免回溯:

/J[^.]*/

然而,这并不完全等同于上述正则表达式。

答案 1 :(得分:0)

这个正则表达式:

/John(?![.])/

将匹配John,但不匹配John。它使用负向look- 提前断言(而不是在后面看)。

如果你想匹配“John”以外的全名,你需要更加具体地说明你在比赛中做了什么和不想做什么,因为J*会匹配零个或多个J

编辑:显然我误读了@ amon帖子的*。前瞻与后视仍然适用。