正则表达式问题:为什么这不匹配?

Regex trouble: Why does this not match?

我需要一个始终匹配 (!) 的正则表达式来提取 Postgresql 中的数据(使用 regexp_matches)。

这是一个示例输入:

#link showcatalog=123 text=blurb

我的正则表达式:

/(?:showcatalog=([0-9]+))?/

我用 Perl 试过这个:

perl -e 'use Data::Dumper; print Dumper([ "#link showcatalog=123 text=blurb" =~ /(?:showcatalog=([0-9]+))?/ ]);'

并期望 $VAR1 = [ 123 ] 但得到了 $VAR1 = [ undef ]。我不明白,因为“?”是贪婪的,而且它的行为不是这样的。我有什么不明白的?我试过 regex101.com 但这对我没有帮助。如何得到预期的结果?

不是应该优先匹配文本吗,比较贪心?

如果没有,就去匹配,比如在

#link text=blurb"

我只想得到$VAR1 = [ undef ]

?贪心是正确的,但是匹配零次或一次直到满足条件。贪心就是在这个"zero or one"条件下。在您的情况下,由于整个正则表达式是可选的(由 ? 包围),因此优先考虑 "zero" 时间,因为它是第一种可能性。

引擎一步步来,试图匹配你的表情。在字符串的第一个字符中,零匹配已经是可能的,因此不会返回任何内容。从这个意义上说,? 是贪婪的,如果零或一个是可能的(它将选择一个),但如果匹配已经满足,则返回它。贪婪并不优先于是否匹配整个表达式。如果是指:如果有取零或取一的可能。

你的 [0-9] 刚好 \d。所以如果你需要提取数字你可以使用这个:

/showcatalog=(\d+)/

要提取整个文本(showcatalog 和数字)只需使用

/(showcatalog=\d+)/

类似于您的命令:

perl -e 'use Data::Dumper; print Dumper([ "#link showcatalog=123 text=blurb" =~ /showcatalog=(\d+)/ ]);'

在 Perl 脚本中:

my $string1 = "#link showcatalog=123 text=blurb";
my ($number1) = $string1 =~ /showcatalog=(\d+)/;
print Dumper([ $number1 ]);

my $string2 = "#link text=blurb";
my ($number2) = $string2 =~ /showcatalog=(\d+)/;
print Dumper([ $number2 ]);

你可以强制一个undef出现,如果你使用像这样的东西:

/(?:.*showcatalog=(\d+))?/

问题是您只得到第一个匹配项,其中 (?:...)? 组是空的,这要归功于最后的 ?。它可以匹配字符串中的任何位置;要查看所有可能的匹配项,请使用 /g 修饰符:

perl -e 'use Data::Dumper; print Dumper([ "#link showcatalog=123 text=blurb" =~ /(?:showcatalog=([0-9]+))?/g ]);'
$VAR1 = [
          undef,
          undef,
          undef,
          undef,
          undef,
          undef,
          '123',
          undef,
          undef,
          undef,
          undef,
          undef,
          undef,
          undef,
          undef,
          undef,
          undef,
          undef,
          undef
        ];

你需要使用这个模式

 /.*showcatalog=([0-9]+)|/

.* 强制回溯以在字符串中的任何位置查找 showcatalog=([0-9]+),并且 | 还允许空字符串匹配(它始终会匹配)如果第一个替代项失败,将 </code> 设置为 <code>undef

perl -MData::Dumper -e 'print Dumper [ "#link showcatalog=123 text=blurb" =~ /.*showcatalog=([0-9]+)|/ ]'

输出

$VAR1 = [
          '123'
        ];
perl -MData::Dumper -e 'print Dumper [ "#link xxx=123 text=blurb" =~ /.*showcatalog=([0-9]+)|/ ]'

输出

$VAR1 = [
          undef
        ];