说,我有一行包含以下字符串:
"$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部分,但是到目前为止我无处可去。
感谢您提供的任何慷慨提供的指导:)
答案 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