PCRE 负先行给出意外的匹配

PCRE negative lookahead gives unexpected match

我想要一个 Perl 正则表达式匹配 std::foo 但不匹配 std::foo::bar。这是我目前所拥有的:

/((?<!\w)([A-Za-z0-9_]+)::([A-Za-z0-9_]+))(?!:)/

这匹配 std::foo::barstd::fo,但我希望整个匹配对于此输入失败,而不是给出部分匹配。

我真正想要什么正则表达式?

只需在否定前瞻之前添加 \b 以确保存在单词边界,并且不要忘记在第一个否定前瞻中添加 :。否则它会匹配第二部分。

((?<![:\w])([A-Za-z0-9_]+)::([A-Za-z0-9_]+))\b(?!:)

只有当它前面没有非space字符时,它才会匹配导入字符串。

(?<!\S)([A-Za-z0-9_]+)::([A-Za-z0-9_]+)\b(?!:)

DEMO

除了\b你还可以:

  • 使用所有格匹配来避免回溯到 foo((?<!\w)([A-Za-z0-9_]+)::([A-Za-z0-9_]++))(?!:)
  • 将单词字符class添加到前瞻中,因此它不能回溯到foo((?<!\w)([A-Za-z0-9_]+)::([A-Za-z0-9_]+))(?![:\w])

此解决方案在模式 \w++foo 部分使用 占有量词 。这意味着它会在找到一系列 "word" 字符后拒绝回溯,即使模式的其余部分——否定的前瞻——然后失败了。我还必须更改否定后视以拒绝单词字符 或冒号 : 以防止 baz::std::foo 之类的东西匹配

主要是的整理。它使用 \w 而不是文字字符 class,使用 /x 修饰符添加布局,并删除不必要的括号。它还提供了一个工作示例

use strict;
use warnings 'all';
use feature 'say';

my $s = 'match std::foo but not match std::foo::bar.';

say  while $s =~ / (?<![\w:]) ( \w+::\w++) (?!:) /gx;

输出

std::foo

匹配整个字符串 std::foo::bar 而不是部分值 我们可以使用这个正则表达式

((\b(.+)\b)+?[::]{2}.+)

它会给你两个火柴

  • std::foo
  • std::foo::bar