我正在尝试使用正则表达式将字符串分成两部分。该字符串的格式如下:
text to extract<number>
我一直在使用(.*?)<
并且<(.*?)>
工作正常,但是在稍微阅读了正则表达式之后,我才开始想知道为什么我需要?
在表达式中。我只是在通过这个网站找到它们之后才这样做,所以我不确定有什么区别。
我正在尝试使用正则表达式将字符串分成两部分。该字符串的格式如下:
text to extract<number>
我一直在使用(.*?)<
并且<(.*?)>
工作正常,但是在稍微阅读了正则表达式之后,我才开始想知道为什么我需要?
在表达式中。我只是在通过这个网站找到它们之后才这样做,所以我不确定有什么区别。
默认情况下,正则表达式中的重复是贪婪的:他们尝试匹配尽可能多的代表,当这不起作用并且他们不得不回溯时,他们尝试一次匹配更少的代表,直到整个模式的匹配是成立。结果,当匹配最终发生时,贪婪的重复将匹配尽可能多的代表。
?
as 重复量词将此行为更改为非贪婪,也称为不情愿(在例如 Java 中)(有时是“懒惰”)。相反,这种重复将首先尝试匹配尽可能少的重复次数,当这不起作用并且他们不得不回溯时,他们开始一次匹配更多重复次数。结果,当最终发生匹配时,不情愿的重复将匹配尽可能少的重复次数。
让我们比较这两种模式:A.*Z
和A.*?Z
。
给定以下输入:
eeeAiiZuuuuAoooZeeee
这些模式产生以下匹配:
A.*Z
产生 1 场比赛:(AiiZuuuuAoooZ
见rubular.com)A.*?Z
产生 2 个匹配项:AiiZ
和AoooZ
(参见 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
相同的两个匹配项(如 ideone.com 上所示)。就是所谓的否定字符类:它匹配除.A.*?Z
[^Z]
Z
两种模式之间的主要区别在于性能:更严格,否定字符类只能匹配给定输入的一种方式。对此模式使用贪婪或不情愿的修饰符并不重要。事实上,在某些方面,你可以做得更好,并使用所谓的所有格量词,它根本不会回溯。
这个例子应该是说明性的:它显示了贪婪、不情愿和否定字符类模式在给定相同输入的情况下如何不同地匹配。
eeAiiZooAuuZZeeeZZfff
这些是上述输入的匹配项:
A[^Z]*ZZ
产生 1 场比赛:(AuuZZ
如在 ideone.com 上看到的)A.*?ZZ
产生 1 场比赛:(AiiZooAuuZZ
如在 ideone.com 上看到的)A.*ZZ
产生 1 场比赛:(AiiZooAuuZZeeeZZ
如在 ideone.com 上看到的)这是他们匹配的视觉表示:
___n
/ \ n = negated character class
eeAiiZooAuuZZeeeZZfff r = reluctant
\_________/r / g = greedy
\____________/g
这些是指向 stackoverflow 上的问题和答案的链接,涵盖了一些可能感兴趣的主题。
这是贪婪量词和非贪婪量词之间的区别。
考虑输入101000000000100
。
使用1.*1
,*
是贪心的 - 它会一直匹配到最后,然后回溯直到它可以匹配1
,留下1010000000001
.
.*?
是非贪婪的。*
将不匹配任何内容,但随后将尝试匹配额外字符,直到匹配1
,最终匹配101
.
所有量词都有一个非贪婪模式:.*?
, .+?
, .{2,6}?
, 和 even .??
。
在您的情况下,类似的模式可能是<([^>]*)>
- 匹配除大于号以外的任何字符(严格来说,它匹配除>
中间<
和之外的零个或多个字符>
)。
请参阅量词备忘单。
假设您有:
<a></a>
<(.*)>
将匹配a></a
where as <(.*?)>
would match a
。后者在 的第一场比赛后停止>
。它检查一个或 0 个匹配,.*
后跟下一个表达式。
第一个表达式<(.*)>
在匹配第一个时不会停止>
。它将一直持续到 的最后一场比赛>
。