-
Notifications
You must be signed in to change notification settings - Fork 196
正则表达式possessive、greediness和laziness区别
正则表达式(Regular Expression)的贪婪模式(Greediness)和懒惰模式(Laziness)用于决定匹配的排列顺序。
贪婪模式首先尝试尽可能多的匹配,最终正则表达式引擎回溯找到匹配。懒惰模式首先尝试尽可能少的匹配,最终正则表达式引擎逐行扩展匹配,以找到整体匹配。因为贪婪模式和懒惰模式改变了排列顺序,它们可以改变整体正则表达式匹配。但是,它们不会改变正则表达式引擎为防止遗漏可能的匹配项,将进行回溯以便尝试所有排列可能。
Possessive Match会阻止正则表达式引擎尝试所有排列可能性,主要好处在于提高性能。
与贪婪模式类似,Possessive Match也是尽可能多的匹配,不同之处在于它不会放弃匹配作为引擎回溯。Possessive Match通过在运算符后面添加+
生成。*
是贪婪匹配,*?
是懒惰匹配,*+
是possessive匹配,++
、?+
和{n,m}+
都是possessive匹配。
在iOS正则表达式语法全集内可以查看懒惰匹配、贪婪匹配及possessive匹配都有哪些。
来看一下模式"[^"]*+"
匹配字符串"abc"的过程,"
匹配左双引号“,[^"]
匹配字符a、b和c,因为*
表示零次、一次或多次,"
匹配最后的字符“,到此,找到了完整匹配。在这里使用贪婪模式或possessive match匹配结果没有区别,Possessive match因为不需要记录回溯位置,会更高效些。
在遇到正则表达式匹配失败时,Possessive Match对于性能的提高更为明显。如果上面的字符串为“abc,没有右双引号,这里的匹配过程与上面类似,不过最后的"
会匹配失败。当使用Possessive Match时,失败后不进行回溯,即不会放弃已匹配的部分以便尝试其它排列,所以在右双引号"
匹配失败时,整个匹配尝试立即停止。
如果用的模式为"[^"]*"
,正则表达式引擎会进行回溯。当最后的"
匹配失败时,[^"]*
进行回溯,放弃最后一个匹配,即匹配字符改变为ab,"
尝试匹配字符c,失败。[^"]*
进行回溯,放弃一个匹配,即匹配字符改变为a,"
尝试匹配字符b,失败。[^"]*
再次回溯,放弃一个匹配,即不匹配任何字符,"
尝试匹配字符a,失败。只有到这时,所有回溯位置用完,正则表达式引擎才会放弃匹配。最终,正则表达式执行了很多无用匹配尝试。
Possessive Match最大的好处是可以加快正则表达式的匹配速度,可以让正则表达式更快的失败。在上面的例子中,我们知道regex不可能错过右双引号,所以在匹配失败时没有必要进行回溯,可以通过使用Possessive Match避免回溯。
只有一个回溯时可能无法觉察到效率的提升,当这些运算符嵌套在一个组内,且都是重复*
,并且该组也重复时,此时的回溯会是灾难性的,这时使用Possessive Match会对性能有明显提高。
使用Possessive Match可以改变匹配的结果。如模式".*"
匹配字符串"abc"x的结果为“abc”,模式".*+"
不能匹配该字符串。
在上面的两个regex中,第一个"
匹配左双引号“,Possessive Match的.
匹配剩余字符串abc"x,右双引号"
匹配失败,因为不能回溯,没有其它排列可能,整个匹配失败。贪婪匹配开始时匹配剩余字符串abc“x,右双引号"
匹配失败。开始回溯,一次回溯一个匹配,在这里为一个字母或符号。回溯匹配为abc","
匹配字符x失败。回溯匹配为abc,"
匹配右双引号“,匹配完成,匹配项为"abc"。
当使用Possessive Match时,要注意Possessive匹配符+
前后的字符不能匹配。正如上面的例子,possessive match前的.
能够匹配possessive match后的右双引号,这时就不能使用possessive match。
如果想要系统了解正则表达式,请查看我的另一篇文章正则表达式NSRegularExpression。
参考资料: