今天我们接着学习一些正则表达式高级的话题。
模式修饰符
当我们做字符串查找的时候,有很多情况我们都需要忽略字符串大小写,但是不是所有的编辑器都像grep一样提供简单的 -i 选项,比如,当我们在使用Notepad++的时候,又或者当我们在.Net,Java里面使用的时候,我们需要忽略大小写匹配正则表达式,有没有什么办法呢?
答案是肯定的,这个时候我们就需要用到模式修饰符。常用的模式修饰符有如下几种:
字符 | 模式 |
i | 不区分大小写 |
x | 宽松排列和注释模式 |
s | 点号通配模式 |
m | 增强的行锚点模式 |
其中我们最可能用上的就是不区分大小写的模式修饰符,使用语法(?i)打开模式让不区分大小写开始工作,之后如果不需要不区分大小写,使用语法(?-i)关闭模式,让我们看一个例子。
现有一个目标字符串,可能是Hello, 也可能是hello, 甚至还可能是HELLO, 要想很轻松的匹配,我们最好的选择是使用模式(?i)hello去进行匹配,否则,我们就只有使用一个很丑陋的模式Hello|hello|HELLO...。进一步说,如果目标字符串是Hello World, 那么模式(?i)hello\s+world匹配,但是(?i)hello(?-i)\s+world却无法匹配,因为过早的关掉了不区分大小写的模式。
忽略优先量词
考虑量词,*,?,+和{min, max},这些量词的本性是匹配优先,即贪婪匹配,比如.*可以吃掉目标字符串的一切。在有些情况下这种行为是我们乐于见到的,但是在一些情况下,这种特性会造成极大的性能问题,考虑使用.*a来匹配目标字符串abcdefghj..xyz,在NFA引擎下面这个匹配的性能会低到令人发指(原因等我们讲到正则表达式引擎的时候会说明)。所以偶尔我们也希望量词能改改它们的秉性,仅仅只匹配最低程度即可,总结来看:
目标文本 | 量词 | 效果 | 忽略优先量词 | 忽略优先效果 |
aaab | a* | 匹配aaa | a*? | 不匹配任何东西 |
aaab | a? | 匹配a | a?? | 不匹配任何东西 |
aaab | a+ | 匹配aaa | a+? | 匹配a |
aaab | a{2,3} | 匹配aaa | a{2,3}? | 匹配aa |
从上面我们可以看出,在量词后面加?使量词变为忽略优先量词,忽略优先量词仅仅匹配满足自己最小要求的部分,当然,这是在不影响整个字符串的匹配成功的前提下,如果字符串匹配要求忽略优先量词“从大局出发”,必须匹配更多的内容,量词也是义不容辞的。比如,用a*?b匹配aaab,为了匹配成功,a*?也会匹配aaa。
占有优先量词
还有一种量词叫占有优先量词,在量词 *, ?, + 和 {min,max}后面添加+即可,占有优先量词最基本的特征就是,他一旦匹配成功,就不会改变,哪怕造成正规字符串匹配失误也在所不惜。比如,用.*b来匹配aaab是完全没有问题的,前面.*先匹配整个字符串,后面发现有个b需要匹配,.*会从自己已有的匹配中退出一部分字符来尝试满足这个条件,当然,这样的结果是皆大欢喜。另一方面,如果这里我们使用的是模式.*+b来匹配,那么这个匹配会失败,因为.*+是占有优先,不会为了整个字符串的匹配与否退出字符。
占有优先量词很像固化分组(?>),都是匹配之后就不会变化,在没有完全熟悉正则表达式的原理和引擎之前,建议不要轻易使用,否则会给自己带来不必要的麻烦。
接下来我们会学习正则表达式的引擎,这是正则表达式的核心,了解引擎以及匹配原理之后,我们在使用正则表达式的时候就会更加得心应手,敬请期待!