如果我试图将引号分隔的字符串与正则表达式匹配,则以下哪个是“更好”(其中“更好”意味着效率更高且不太可能做出意外事情):
/"[^"]+"/ # match quote, then everything that's not a quote, then a quote
或
/".+?"/ # match quote, then *anything* (non-greedy), then a quote
假设这个问题是空字符串(即“”)不是问题。在我看来(没有正则表达式新手,但肯定没有专家),这些将是等价的。
更新:经过反思,我认为将+
字符更改为*
无论如何都会正确处理空字符串。
答案 0 :(得分:34)
你应该使用第一名,因为第二名是不好的做法。考虑到您之后的开发人员想要匹配后跟感叹号的字符串。他应该使用:
"[^"]*"!
或:
".*?"!
当您有主题时会出现差异:
"one" "two"!
第一个正则表达式匹配:
"two"!
而第二个正则表达式匹配:
"one" "two"!
始终尽可能具体。尽可能使用否定的字符类。
另一个区别是[^“] *可以跨行,而。*除非你使用单行模式。[^”\ n] *也排除了换行符。
至于回溯,第二个正则表达式会回溯它匹配的每个字符串中的每个字符。如果缺少结束引号,则两个正则表达式都将回溯整个文件。只有回溯的顺序不同。因此,从理论上讲,第一个正则表达式更快。在实践中,你不会注意到差异。
答案 1 :(得分:12)
更复杂,但是它处理转义引号并且还转义了反斜杠(转义反斜杠后跟引号不是问题)
/(["'])((\\{2})*|(.*?[^\\](\\{2})*))\1/
示例:
“hello \”world“匹配”hello \“world”
“hello \\”world“匹配”hello \\“
答案 2 :(得分:9)
我建议:
([\"'])(?:\\\1|.)*?\1
但这只是因为它处理了转义的引用字符并且允许'和'都是引用字符。我还建议查看这篇深入探讨这个问题的文章:
http://blog.stevenlevithan.com/archives/match-quoted-string
但是,除非您遇到严重的性能问题或无法确定嵌入式引号,否则请使用更简单,更易读的内容:
/".*?"/
我必须承认,非贪婪的模式不是基本的Unix风格的“ed”正则表达式,但它们变得非常普遍。我仍然不习惯像(?:stuff)那样对运营商进行分组。
答案 3 :(得分:5)
我会说第二个更好,因为当终止"
丢失时它会更快失败。第一个将回溯字符串,这是一个可能很昂贵的操作。如果使用perl 5.10,则另一种正则表达式为/"[^"]++"/
。它传达的意思与版本1的含义相同,但与版本2一样快。
答案 4 :(得分:3)
我会选择第二,因为它更容易阅读。但是我仍然喜欢匹配空字符串,所以我会使用:
/".*?"/
答案 5 :(得分:1)
从性能角度来看(对于长字符串来说非常沉重,长时间运行的循环),我可以想象
"[^"]*"
比
快".*?"
因为后者会对每一步进行额外的检查:偷看下一个字符。前者可以无意识地滚动字符串。
正如我所说,在现实世界的情景中,这几乎不会引人注意。因此,我会选择二号(如果我目前的正则表达式支持它,那就是),因为它更具可读性。否则就是第一名。
答案 6 :(得分:1)
当输入中的边界字符(在您的示例中为双引号)出现时,使用否定字符类可防止匹配。
你的例子#1:
/"[^"]+"/ # match quote, then everything that's not a quote, then a quote
只匹配最小的一对匹配的引号 - 非常好,大部分时间都是你需要的。但是,如果你有嵌套的引号,并且你对最大的匹配引号对(或所有匹配的引号)感兴趣,那么你的情况要复杂得多。
幸运的是Damian Conway准备好了救援:如果您发现有多个匹配的引号,那么Text::Balanced就在您身边。它还具有匹配其他配对标点符号的优点,例如,括号中。
答案 7 :(得分:0)
我更喜欢第一个正则表达式,但这肯定是一个品味问题。
第一个可能更有效率?
Search for double-quote
add double-quote to group
for each char:
if double-quote:
break
add to group
add double-quote to group
对于涉及回溯的事情有点复杂吗?
答案 8 :(得分:0)
考虑到我甚至不知道“*?”事情直到今天,我已经使用正规表达20多年了,我投票支持第一个。它肯定会清楚你要做的是什么 - 你试图匹配一个不包含引号的字符串。