为什么pos()报告甚至与非捕获组匹配?

时间:2016-04-14 15:08:15

标签: regex perl pcre

我希望在参数化的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一样吗?

1 个答案:

答案 0 :(得分:3)

最简单的解决方案是在检查pos之前检查捕获的parens是否实际捕获了某些东西:

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

这会产生预期的结果。

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