【问题标题】:Regex trouble: Why does this not match?正则表达式的麻烦:为什么这不匹配?
【发布时间】:2017-07-19 09:47:10
【问题描述】:

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

【问题讨论】:

  • 你能为你的正则表达式提供一些输入数据吗?
  • @JohnDoe:输入是“#link showcatalog=123 text=blurb”。如果匹配,则预期输出为“[ match ]”,否则为“[ undef ]”。
  • 所以你真正的问题是关于 postgresql 中的select regexp_matches('#link showcatalog=123 text=blurb', '(?:showcatalog=([0-9]+))?');,对吧?我认为所有这些 perl 东西并没有使问题更清楚。
  • 为什么你添加了这个??这意味着如果该组不在这里,它也匹配。你能解释一下真正的目标吗?
  • @sidyll:随意!

标签: regex perl pcre regex-greedy


【解决方案1】:

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

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

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

【讨论】:

  • ?: 不是前瞻
  • 这是一个非捕获分组
  • 对不起@Dada,感谢您的关注,我完全误读了
  • 这似乎没有回答这个问题。你检查更新的 perl 命令是否给出了预期的结果?
  • @DenysSéguret 是的
【解决方案2】:

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

【讨论】:

  • Can't find string terminator "'" anywhere before EOF at -e line 1. 只是我想知道为什么在 Windows 7 cmd 中检查上述代码perl -e 'use Data::Dumper; print Dumper([ "#link showcatalog=123 text=blurb" =~ /(?:showcatalog=([0-9]+))?/g ]);' 时会出现此错误
  • @ssr1012:在windows中,必须在命令行中使用外双引号。
  • 啊,现在我理解了这种行为,感谢您阻止我挠头。你知道如何表达一个正则表达式来实现预期的输出吗?
  • @Searle:坦率地说,我不明白你想要达到什么目的。什么输入是可能的,什么输出是预期的?
  • 非常感谢。我明白了。
【解决方案3】:

你需要使用这个模式

 /.*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
        ];

【讨论】:

  • 这很聪明,谢谢。我希望你同意我接受 sidyll 的回答,因为他早些时候发布了他的解决方案......
  • @Searle:这完全取决于你选择哪一个,但我看不到 sidyll 的几个答案中的任何一个。你选了哪一个?
  • 带有 /(?:.*showcatalog=(\d+))?/ 的那个 - 诀窍(对我来说)是将 .* 添加到非捕获组。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-24
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-25
相关资源
最近更新 更多