为什么我的非贪婪Perl正则表达式仍然匹配太多?

时间:2009-10-21 05:52:29

标签: regex perl

说,我有一行包含以下字符串:

"$tom" said blah blah blash.  "$dick" said "blah blah blah". "$harry" said blah blah blah.

我要提取

"$dick" said "blah blah blah"

我有以下代码:

my ($term) = /(".+?" said ".+?")/g;
print $term;

但它给了我比我更多的东西:

"$tom" said blah blah blash.  "$dick" said "blah blah blah"

我尝试使用非捕获的parens将我的模式整体分组:

my ($term) = /((?:".+?" said ".+?"))/g;

但问题仍然存在。

我已经读过了学习Perl的Nongreedy Quantifiers部分,但是到目前为止我无处可去。

感谢您提供的任何慷慨提供的指导:)

4 个答案:

答案 0 :(得分:18)

问题在于,即使它并不贪心,它仍然在不断尝试。正则表达式没有看到

"$tom" said blah blah blash.

并且想“噢,”说“之后的东西没有引用,所以我会跳过那个。”它认为“好吧,之后的东西”说“没有引用,所以它仍然必须是我们引用的一部分。”所以".+?"匹配

"$tom" said blah blah blash.  "$dick"

你想要的是"[^"]+"。这将匹配两个引号,包含任何不是引号的内容。所以最终解决方案:

("[^"]+" said "[^"]+")

答案 1 :(得分:3)

不幸的是"是一个特殊的角色,需要谨慎对待。使用:

my ($term) = /("[^"]+?" said "[^"]+?")/g;

它应该可以正常工作(它适合我...!)。即显式匹配“非双引号”的序列而不是任意字符的序列。

答案 2 :(得分:3)

其他人已经提到了如何解决这个问题。

我将回答您如何调试此问题:您可以通过使用更多捕获来查看正在发生的事情:

 bash$ cat story | perl -nle 'my ($term1, $term2, $term3) = /(".+?") (said) (".+?")/g ; 
      print "term1 = \"$term1\" term2 = \"$term2\" term3 = \"$term3\" \n"; '
 term1 = ""$tom" said blah blah blash.  "$dick"" term2 = "said" term3 = ""blah blah blah""

答案 3 :(得分:2)

你的问题是你的正则表达式有两种可能的匹配,你想要的那种(较短的一种)和正则表达式引擎选择的那种。引擎选择该特定匹配,因为它更喜欢在字符串中较早开始的匹配,并且对于稍后开始且较短的匹配较长。换句话说,早期比赛胜过较短的比赛。

要解决这个问题,你需要让你的正则表达式更具体(就像告诉引擎$ term不应该包含任何引号一样。最好让你的正则表达式尽可能具体。

有关正则表达式的更多细节和问题,我推荐Jeffrey Friedl的优秀书籍:Mastering Regular Expressions