.* 和有啥不一样?和 .* 正则表达式?
Posted
技术标签:
【中文标题】.* 和有啥不一样?和 .* 正则表达式?【英文标题】:What is the difference between .*? and .* regular expressions?.* 和有什么不一样?和 .* 正则表达式? 【发布时间】:2011-03-05 17:52:51 【问题描述】:我正在尝试使用正则表达式将字符串分成两部分。字符串格式如下:
text to extract<number>
我一直在使用(.*?)<
和<(.*?)>
,它们工作得很好,但是在稍微阅读了正则表达式之后,我开始想知道为什么我需要在表达式中使用?
。我只是在通过这个网站找到它们后才这样做的,所以我不确定有什么区别。
【问题讨论】:
另见***.com/questions/2301285/… 【参考方案1】:假设你有:
<a></a>
<(.*)>
将匹配 a></a
,而 <(.*?)>
将匹配 a
。
后者在>
的第一场比赛后停止。它检查一个
或 0 个匹配 .*
后跟下一个表达式。
第一个表达式<(.*)>
在匹配第一个>
时不会停止。它会一直持续到>
的最后一场比赛。
【讨论】:
这个比上面的解释更容易理解。 解释应该是这样的。【参考方案2】:这是贪心量词和非贪心量词的区别。
考虑输入101000000000100
。
使用1.*1
、*
是贪心的——它会一直匹配到最后,然后回溯直到它可以匹配1
,留下1010000000001
。.*?
是非-贪婪的。 *
将不匹配任何内容,但随后会尝试匹配多余的字符,直到匹配 1
,最终匹配 101
。
所有量词都有非贪婪模式:.*?
、.+?
、.2,6?
,甚至是.??
。
在您的情况下,类似的模式可能是 <([^>]*)>
- 匹配除大于号以外的任何字符(严格来说,它匹配 <
和 >
之间除 >
之外的零个或多个字符) .
见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.*Z
和 A.*?Z
。
给定以下输入:
eeeAiiZuuuuAoooZeeee
这些模式产生以下匹配:
A.*Z
产生 1 个匹配项:AiiZuuuuAoooZ
(see on rubular.com)
A.*?Z
产生 2 个匹配项:AiiZ
和 AoooZ
(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。以上是关于.* 和有啥不一样?和 .* 正则表达式?的主要内容,如果未能解决你的问题,请参考以下文章
nx 和 Lerna 和有啥不一样? (monorepos)