使用技巧
1) 尽量重用已编译的正则表达式
在 Java 中使用正则表达式的时候我们需要先编译,所以应该尽量重用我们已经定义的正则表达式。
2) 正则表达式的很多优化技巧都是围绕着“减少回溯”这样一个原则进行优化的。
3) 使用正确的边界匹配器(^、$、\b、\B等),限定搜索字符串位置
^ 匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”。
\B 匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
4) 使用具体的元字符、字符类(\d、\w、\s等),少用”.”字符
\d 匹配一个数字字符。等价于[0-9]。
\w 匹配包括下划线的任何单词字符。等价于“[A-Za-z0-9_]”。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
5) 使用正确的量词(+、*、?、{n,m}),如果能够限定长度,匹配最佳
* 匹配前面的子表达式零次或多次。例如,zo*能匹配“z”以及“zoo”。*等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。
? 匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“does”或“does”中的“do”。?等价于{0,1}。
{n} n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。
{n,} n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。
{n,m} m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。
6) 使用非捕获组、原子组,减少没有必要的字匹配捕获用(?:)
(?:pattern) 匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分是很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。
7) 不要滥用括号
在需要的时候使用括号,在其他时候使用括号会阻止某些优化措施。除非你需要知道.*匹配的最后一个字符,否则请不要使用(.*)。
8) 不要滥用字符组
例如 ^.*[:] 这样会付出处理字符组的代价,而实际上这个式子并需不要用到字符组提供的多字符匹配功能,我认为,当一个字符是元字符时例如 . 或 * 应该使用\.或\*表示,在比如需要 [Ff],应当使用不缺分大小写的匹配,而不是字符组。
9) 使用起始锚点
除非是及其罕见的情况,否则以 .* 开头的正则表达式都应该在最前面添加 ^ 或者\A 如果这个正则表达式在某个字符串的开头不能匹配,那么显然在其他位置它也不能匹配。添加锚点无论是手工添加还是通过优化自动添加都能够配合开头字符/字符串/字串识别优化,节省大量不必要的工作。
10) 将文本独立出来
1、从量词中提取必须的元素
用 xx* 替代 x+ 能够暴露必须匹配的 x 同样,用-----{0,2}代替-{5,7}。
2、提取多选结构开头的必须元素
用th(?:is|at)替代(?:this|that),就能暴露出必须的th。如果不同的多选分支的结尾部分相同,我们也可以从右面"提取"。例如(?:optim|standard)ization 。
11) 将锚点独立出来
1、在表达式前面独立出 ^ 和 \G
^(?:abc|123)和(^abc|^123)在逻辑上是等价的,但是许多正则引擎指挥对第一个表达式使用开头字符/字符串/字串识别优化。所以第一种办法的效率高得多。
2、在表达式末尾独立出$
虽然 abc$|123$ 和 (?:abc|123)$ 在逻辑上是等价的,但优化的表现可能不同。目前只对Perl有效。
12) 注意运算符的优先级
正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。相同优先级的从左到右进行运算,不同优先级的运算先高后低。下表从最高到最低说明了各种正则表达式运算符的优先级顺序:
正则表达式 - 运算符优先级
http://www.w3cschool.cc/regexp/regexp-operator.html
注意细节
1) | 或者符号
| 的优先级最低,如果想优先匹配,请使用(?:)或().
例如想匹配 a123 或 b123
请勿使用 a|b123 ,a|b123 匹配的是 a 或 b123
请使用(?:a|b)123,注意尽量使用非捕获组(?:),减少使用捕获组()
2) [] 中括号
[]表示的是字符簇的概念,使用字符簇需注意:
Ø 字符之间本就是或的关系,所有不需要使用“|”做风格(如果想匹配字符串簇,请阅读上一条);
Ø “-”在字符簇中是表示区间的概念,如果要匹配“-”,请使用转移后的“\-”;
Ø 在字符簇中“.”只匹配“.”本身,不匹配其他字符,但为了书写规范,建议还是使用“\.”。
[a-z] //匹配所有的小写字母
[A-Z] //匹配所有的大写字母
[a-zA-Z] //匹配所有的字母
[0-9] //匹配所有的数字
[0-9\.\-] //匹配所有的数字,句号和减号
[ \f\r\t\n] //匹配所有的白字符
3) *?,+?,?? 量词加问号,非贪婪匹配
正则默认采用的是贪婪匹配,即尽可能多的去匹配。如果想尽量少的匹配,请在量词后面加上“?”
例如:
<div id="a" name="a">abcd1234</div><div id="b" name="b">abcd1234</div>
<div.*</div> 匹配 <div id="a" name="a">abcd1234</div><div id="b" name="b">abcd1234</div>
<div.*?</div> 匹配 <div id="a" name="a">abcd1234</div>
? 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。
参考资料
http://www.w3cschool.cc/regexp/regexp-metachar.html
http://www.cnblogs.com/kissdodog/archive/2013/04/27/3047750.html
http://blog.csdn.net/shangboerds/article/details/7613928
http://blog.chacuo.net/329.html
http://my.oschina.net/o0Kira0o/blog/138516