.* 和有啥不一样?和 .* 正则表达式?

Posted

技术标签:

【中文标题】.* 和有啥不一样?和 .* 正则表达式?【英文标题】:What is the difference between .*? and .* regular expressions?.* 和有什么不一样?和 .* 正则表达式? 【发布时间】:2011-03-05 17:52:51 【问题描述】:

我正在尝试使用正则表达式将字符串分成两部分。字符串格式如下:

text to extract<number>

我一直在使用(.*?)&lt;&lt;(.*?)&gt;,它们工作得很好,但是在稍微阅读了正则表达式之后,我开始想知道为什么我需要在表达式中使用?。我只是在通过这个网站找到它们后才这样做的,所以我不确定有什么区别。

【问题讨论】:

另见***.com/questions/2301285/… 【参考方案1】:

假设你有:

<a></a>

&lt;(.*)&gt; 将匹配 a&gt;&lt;/a,而 &lt;(.*?)&gt; 将匹配 a。 后者在&gt; 的第一场比赛后停止。它检查一个 或 0 个匹配 .* 后跟下一个表达式。

第一个表达式&lt;(.*)&gt; 在匹配第一个&gt; 时不会停止。它会一直持续到&gt;的最后一场比赛。

【讨论】:

这个比上面的解释更容易理解。 解释应该是这样的。【参考方案2】:

这是贪心量词和非贪心量词的区别。

考虑输入101000000000100

使用1.*1* 是贪心的——它会一直匹配到最后,然后回溯直到它可以匹配1,留下1010000000001.*? 是非-贪婪的。 * 将不匹配任何内容,但随后会尝试匹配多余的字符,直到匹配 1,最终匹配 101

所有量词都有非贪婪模式:.*?.+?.2,6?,甚至是.??

在您的情况下,类似的模式可能是 &lt;([^&gt;]*)&gt; - 匹配除大于号以外的任何字符(严格来说,它匹配 &lt;&gt; 之间除 &gt; 之外的零个或多个字符) .

Quantifier Cheat Sheet

【讨论】:

啊太棒了,我喜欢除了 > 符号之外的最后一个! 你能否解释或举例说明贪婪的? 与非贪婪的?? 有何不同? 当然。对于字符串"abc",正则表达式/\w\w?\w/ 将匹配完整的字符串"abc" - 因为? 是贪婪的。 /\w\w??\w/ 是惰性的 - 它只会匹配 "ab"。如果稍后失败,它只会回溯并匹配"abc"【参考方案3】:

关于贪婪与非贪婪

默认情况下,正则表达式中的重复是贪婪:他们尝试匹配尽可能多的代表,当这不起作用并且他们不得不回溯时,他们尝试在一个时间,直到找到整个模式的匹配。因此,当匹配最终发生时,贪婪的重复将尽可能匹配 许多 个重复。

? 作为重复量词将此行为更改为非贪婪,也称为不情愿 (in e.g. Java)(有时也称为“懒惰”)。相反,此重复将首先尝试匹配尽可能 少数 个重复,当这不起作用并且他们必须回溯时,他们开始一次匹配一个更多重复。因此,当匹配最终发生时,不情愿的重复将尽可能匹配 少数 次。

参考文献

regular-expressions.info/Repetition - Laziness instead of Greediness

示例 1:从 A 到 Z

让我们比较一下这两种模式:A.*ZA.*?Z

给定以下输入:

eeeAiiZuuuuAoooZeeee

这些模式产生以下匹配:

A.*Z 产生 1 个匹配项:AiiZuuuuAoooZ (see on rubular.com) A.*?Z 产生 2 个匹配项:AiiZAoooZ (see on rubular.com)

让我们首先关注A.*Z 的作用。当它匹配第一个A 时,.* 贪婪,首先尝试匹配尽可能多的.

eeeAiiZuuuuAoooZeeee
   \_______________/
    A.* matched, Z can't match

由于Z 不匹配,引擎回溯,然后.* 必须匹配少一个.

eeeAiiZuuuuAoooZeeee
   \______________/
    A.* matched, Z still can't match

这种情况又发生了几次,直到最后我们得出这样的结论:

eeeAiiZuuuuAoooZeeee
   \__________/
    A.* matched, Z can now match

现在Z可以匹配,所以整体模式匹配:

eeeAiiZuuuuAoooZeeee
   \___________/
    A.*Z matched

相比之下,A.*?Z 中的不情愿重复首先匹配尽可能少的.,然后根据需要匹配更多的.。这就解释了为什么它会在输入中找到两个匹配项。

以下是两种模式匹配内容的直观表示:

eeeAiiZuuuuAoooZeeee
   \__/r   \___/r      r = reluctant
    \____g____/        g = greedy

示例:另一种选择

在许多应用程序中,上述输入中的两个匹配项是所需的,因此使用不情愿的.*? 而不是贪婪的.* 以防止过度匹配。然而,对于这个特定的模式,有一个更好的选择,使用否定字符类。

模式A[^Z]*Z 还找到与上述输入(as seen on ideone.com)的A.*?Z 模式相同的两个匹配项。 [^Z] 是所谓的否定字符类:它匹配除Z 之外的任何字符。

两种模式的主要区别在于性能:更严格,否定字符类只能匹配给定输入的一种方式。对此模式使用贪婪或不情愿的修饰符并不重要。事实上,在某些方面,你可以做得更好,使用所谓的所有格量词,它根本不会回溯。

参考文献

regular-expressions.info/Repetition - An Alternative to Laziness、Negated Character Classes 和 Possessive Quantifiers

示例 2:从 A 到 ZZ

这个例子应该是说明性的:它展示了贪婪、不情愿和否定字符类模式如何在相同的输入下以不同的方式匹配。

eeAiiZooAuuZZeeeZZfff

这些是上述输入的匹配项:

A[^Z]*ZZ 产生 1 个匹配项:AuuZZ (as seen on ideone.com) A.*?ZZ 产生 1 个匹配项:AiiZooAuuZZ (as seen on ideone.com) A.*ZZ 产生 1 个匹配项:AiiZooAuuZZeeeZZ (as seen on ideone.com)

这是他们匹配的视觉表示:

         ___n
        /   \              n = negated character class
eeAiiZooAuuZZeeeZZfff      r = reluctant
  \_________/r   /         g = greedy
   \____________/g

相关主题

这些是指向 *** 上的问题和答案的链接,涵盖了一些可能感兴趣的主题。

一个贪婪的重复可以超过另一个

Regex not being greedy enough Regular expression: who's greedier

【讨论】:

我的意思是说 rubular.com,而不是 ideone.com。对其他人:不要为我修改这篇文章,我会在下一次修改时自己做,还有其他例子。随时在 cmets 中提供反馈、建议等,以便我也可以将它们纳入其中。 参见:***.com/questions/3145023/… 此答案已添加到 Stack Overflow Regular Expression FAQ 的“量词 > 更多关于差异...”下。 这个答案真的不愧是被选中的答案!。非常感谢您的详细解释。 我添加了标签non-greedy。为什么,因为问题需要它,还因为它将吸引更多用户使用这个出色的答案。换句话说,如果您给出了一个很好的答案并且答案使用了不在问题中的标签,那么添加标签,因为 OP 不知道标签是 revelent。

以上是关于.* 和有啥不一样?和 .* 正则表达式?的主要内容,如果未能解决你的问题,请参考以下文章

union 和 join 和有啥不一样?

infura 和 geth 和有啥不一样?

nx 和 Lerna 和有啥不一样? (monorepos)

";" 和有啥不一样和 T-SQL 中的“GO”?

agora 和 mux 和有啥不一样?在颤动中流式传输实时视频的最佳方式是啥?

正则表达式、linq表达式、lambda 表达式区别 ,这3者有啥关系和区别么?