为什么 pos() 报告即使与非捕获组也匹配?

Why does pos() report matches even with non-capturing groups?

我想匹配参数化 SQL 查询中的占位符(裸 ?,不带引号),如下所示:

UPDATE `table` SET `col1`=? WHERE `col2`=? AND `x`="??as"

(我知道我应该改用 SQL::Parser。请耐心等待。)

这个正则表达式 (?:`.+?`)|(?:'.+?')|(?:".+?")|(\?) 匹配 `col1`=?`col2`=? 中的裸问号,但跳过 `x`="??as" 中双引号内的问号,正如我希望的那样.您可以在 https://regex101.com/r/iH4aV2/3.

看到这个工作

现在 PCRE 正则表达式 运行。如果我 运行 这段 Perl:

# same regex and test string
my $x = 'UPDATE `table` SET `col1`=? WHERE `col2`=? AND `x`="??as"';          

while ($x =~ /(?:`.+?`)|(?:'.+?')|(?:".+?")|(\?)/g) {
    print "A:".pos($x)."\n";
}

我得到:

A:14
A:25
A:27
A:40
A:42
A:50
A:57

我原以为只得到问号的位置,就像在 regex101 网站上一样:

A:27
A:42

为什么会这样?我可以让 Perl 的正则表达式引擎表现得像 PCRE 吗?

最简单的解决方案就是在检查之前检查捕获括号是否真的捕获了一些东西 pos:

my $x = 'UPDATE `table` SET `col1`=? WHERE `col2`=? AND "x"="??as"';
while($x =~ /(?:`.+?`)|(?:'.+')|(?:".+?")|(\?)/g) {
  if (defined()) {
    print "A:".pos($x)."\n";
  }
}

这会产生预期的结果。

(我的意思是,你可以使用评论中提到的花哨的 (*SKIP)(*FAIL) 动词,但这看起来更简洁)