perl regex停止负面的后卫从下一个贪婪的捕获中取走

时间:2015-09-08 02:42:08

标签: regex perl regex-greedy negative-lookbehind

在perl v5.22.0中使用这个简单的例子:

my $data = "foobar\n";
$data =~ s/(?<!bar)(\s*)$/qux$1/;
print $data;

打印:

foobar
qux

但我不希望$data改变。我也尝试了一些早期版本的perl 5.x,结果相同。

相反,我希望这个字符串使用相同的正则表达式来替换它,但它并没有:

my $data = "foobaz\n";
$data =~ s/(?<!bar)(\s*)$/qux$1/;
print $data;


我不明白为什么会这样。在任何一个星号都应该是贪婪的。我认为$1\n使得负面后卫组与第一个示例中的bar和第二个示例中的baz进行比较。当我使用perl时Regex101说:

  

量词:*在零和无限次之间,尽可能多次,根据需要回馈。

所以在这种情况下会发生什么呢?它会回馈负面的后卫吗?

正如标题所说的那样,真正的问题是我想要阻止后卫吞下第二组。不幸的是,它不是一个字母,只是为了让它更容易理解。同样在perl中,我对负面观察能​​力有所限制,例如&#34;在正则表达式&#34;中没有实现可变长度观察。如果可能,我想要一个与perl 5.8兼容的答案。感谢

2 个答案:

答案 0 :(得分:2)

它确实匹配最后一个位置,在位置为\n之前,在$之后,现在看起来是你的正则表达式:

(?<!bar)(\s*)$
在位置不是bar之前

:匹配

位置为$

,匹配(\s*)$

答案 1 :(得分:2)

我想你想要

$data =~ s/(?<!bar)(?<!\s)(\s*)$/qux$1/;

以下版本将与5.8一起使用,我认为它实际上更快(因为它跳转到字符串的末尾并回溯,而不是在每个位置检查两个看后面):

$data =~ s/
   ^
   (
      (?:
         .*
         (?: [^r\s]
         |   [^a] r
         |   [^b] ar
         )
      )?
   )
   ( \s* )
   \z
/${1}qux$2/sx;

(可以使用$代替\z;它只是一种微优化。)

说明

如果没有m标记,$等同于(?:\n?\z),它表示它匹配字符串末尾和字符串末尾的换行符。这意味着$有两个匹配foobar␊

的位置
foobar␊      (There's a LF at position 6 in
01234567      case your font can't show it.)
      ^^

(?<!bar)阻止第一个位置被考虑,但它允许第二个位置。

  • (?<!bar)(\s*)$匹配位置7的0个字符,因为

    • (?<=bar)匹配位置7的0个字符。
    • (\s*)匹配位置7的0个字符。
    • $匹配位置7的0个字符。

这是唯一可能的匹配,所以贪婪是无关紧要的。