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

时间:2017-02-28 12:12:17

标签: regex perl pcre regex-greedy

我需要一个始终匹配(!)正则表达式来提取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 ]

3 个答案:

答案 0 :(得分:3)

问题是,您只获得了第一场比赛,(?:...)?组由于最终?而为空。它可以匹配字符串中的任何位置;要查看所有可能的匹配项,请使用/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
        ];

答案 1 :(得分:2)

您需要使用此模式

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

.*强制回溯在字符串中的任何位置查找showcatalog=([0-9]+)|也允许空字符串匹配(如果第一个选项失败,它将始终匹配)将$1设置为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
        ];

答案 2 :(得分:1)

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

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

您的[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+))?/