我正在尝试使用正则表达式将字符串拆分为两部分。字符串的格式如下:
text to extract<number>
我一直在使用(.*?)<
和<(.*?)>
工作正常但在阅读了一下regex后,我才开始想知道为什么我需要表达式中的?
。我只是在通过这个网站找到它之后就这样做了所以我不确定它们之间有什么区别。
答案 0 :(得分:143)
默认情况下重复使用正则表达式是贪婪:他们尝试匹配尽可能多的代表,当这不起作用并且他们必须回溯时,他们会尝试匹配少一个代表时间,直到找到整个模式的匹配。因此,当匹配最终发生时,贪婪的重复将匹配为许多代表。
作为重复量词的?
将此行为更改为非贪婪,也称为不情愿(in e.g. Java)(有时“懒惰” “)。相比之下,这种重复将首先尝试匹配尽可能少的少数代表,当这不起作用并且它们必须回溯时,它们会再开始匹配一次。因此,当匹配最终发生时,不情愿的重复将与少数代表匹配。
让我们比较这两种模式: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
以外的任何内容。
两种模式之间的主要区别在于性能:更严格,否定的字符类只能匹配给定输入的一种方式。如果您对此模式使用贪婪或不情愿的修饰符,则无关紧要。事实上,在某些风格中,你可以做得更好,并使用所谓的占有量词,它根本不会回溯。
这个例子应该是说明性的:它显示了贪婪,不情愿和否定的字符类模式在给定相同输入的情况下如何匹配。
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
这些是有关stackoverflow的问题和答案的链接,涵盖了一些可能感兴趣的主题。
答案 1 :(得分:134)
这是贪婪和非贪婪量词之间的区别。
考虑输入101000000000100
。
使用1.*1
,*
是贪婪的 - 它会一直匹配到最后,然后回溯直到它匹配1
,留下1010000000001
。
.*?
不贪心。 *
将不会匹配,但会尝试匹配额外的字符,直到匹配1
,最终匹配101
。
所有量词都有非贪婪模式:.*?
,.+?
,.{2,6}?
,甚至.??
。
在您的情况下,类似的模式可以是<([^>]*)>
- 匹配除了大于号之外的任何内容(严格来说,它匹配>
之外的<
以外的零个或多个字符{{1} }和>
)。
答案 2 :(得分:16)
假设你有:
<a></a>
<(.*)>
会匹配a></a
,其中<(.*?)>
与a
匹配。
后者在>
的第一场比赛后停止。它会检查一个
或.*
的0个匹配,后跟下一个表达式。
匹配第一个<(.*)>
时,第一个表达式>
不会停止。它将一直持续到>
的最后一场比赛。