1.点号匹配换行符 (?s:.)
2.去掉段落首尾的空白:用两个正则
s/^\s+//
s/\s+$//
其它的书写方式都更慢、更复杂,而且结果不正确
3.匹配一个 html 标签,标签内部字符串中可以出现 '<' '>',作者说这是一个相当漂亮的正则表达式:
<("[^"]*"|'[^']*'|[^'">])*>
4. .*? 这是忽略有限量词
5.从一组连着的五位邮编中提取44开头的:
(?:\d\d\d\d\d)*?(44\d\d\d)
注意这个忽略优先量词,在后面表达式失败之前它都不会尝试匹配
6.现代的正则引擎会强迫进行驱动过程,所以同一位置不会发生两次长度为0的匹配
7.匹配 CSV 文件的一行
\\G(?:^|,)(?:((?:[^"]++|"")*+)|([^",]*))
关键点在于第一个括号及左边的部分
8.craft:打造
9.正则引擎的传动装置必然会在第二个自付出重试正则表达式,这或许可以算作一次回溯
10.理解基本原理,就能应付各种情况
11.匹配一个字符串:
"(\\.|[^"])*"
"([^\\"]|\\.)*"
第一个不好,因为每个字符都会引起转义分支的回溯,一个字符串一般转义字符很少,所以两个分支应该调换顺序
12.传统 NFA 遇到匹配就停下来,POSIX NFA 尝试完所有分支才停然后选择最长的匹配,所以可能会很慢
13.对于许多事情来说,牢固理解基本概念对深入学习是非常重要的
14.多选结构的代价很高;字符组的效率比相应的多选结构高
15.everyone's lunch is different 优化各有不同
16.(.+)x\1 期望匹配的是字符串在 x 两侧是相同的
17.^\w+: \w+ 匹配到字符串末尾时,最后的冒号无法匹配,所以回溯机制会强迫 \w+ 逐个交还字符,在每个位置对 : 进行徒劳的尝试。
^(?>\w+): 或 ^\w++: 能避免无谓的劳动
18.常识性优化:只需要依靠常识,就能进行一些极有成效的优化
19.暴露文字文本,提高引擎识别的可能性,配合与文字文本有关的优化措施:x+ -> xx* 这样更快,理论上
20.大多数数据引擎,排除型字符组效率比忽略优先量词高得多:^.*?: -> ^[^:]*:
21.把最可能匹配的分支放前面
22.真正的消除循环解法:"[^\\"]*(\\.[^\\"]*)*"
opening normal* (special normal*)* closing
special 和 normal 开头不能重合,normal 至少匹配一个字符,special 如果加上 * 会很糟糕,因为它无法作为检查点,special 最好是定长的
23.消除循环的例子:
1) <b> </b> 中间可以有任何不是 <b> 或 </b> 的字符:
<b>((?!</?b>).)*</b> ->
<b> (?>[^<])* (?> (?!</?b>)< [^<]*)*</b>
2) ^\w+=([^\n\\]|\\.)* 消除连续行匹配
^\w+=((?>[^\n\\]*) (?>\\. [^\n\\]*)*)
3) CSV 的例子 (?:[^"]|"")* 它看起来很不错,已经区分了 normal 和 special 部分:[^"] ""
\G(?:^|,)
(?:
"((?> [^"]*) (?> "" [^"]*)*)"
|
([^",]*)
)
4)匹配 C 语言注释:/* .*? */ 效果不错,比/* (?: (?!*/).)* */快个几百倍
/* ([^*] | x[^/])* */ 不行,会匹配 /**foo**/ /**/
/* ([^/]|[^*]/)* */ 不行,不能匹配 /*/foo/*/,还会单次匹配多个注释
得这么写:/* ([^*] | *+ [^/*])* *+/,原因:不能让第二个分支匹配过多 *(否则会出界),还要防止有太多 * 跟着一个 /
24.如果能用顺序环视,x之后的字符不能是斜线 -> x(?!/),否则要这么写:x([^/]|$),因为 [^/] 必须消耗一个字符
逆序环视也是一样
25.去掉 C 语言注释的循环,原来是这样的 /* ([^*] | *+ [^/*])* *+/。非常的难,用 x 代替 *
opening 注释开始 /x
normal* 注释文本,包含一个或多个 x,至少消耗一个字符 [^x]*x+
special 不属于结束边界的字符 [^x/]
closing 结尾的斜线 /
/x [^x]*x+ ( [^/x] [^x]*x+)* /
进入括号有两种可能,1.直接进 2.循环进,不管哪种情况,都已经匹配了一个 x 后才进去的。如果下面的字符是斜线,完成;否则去 normal 继续循环。
26.如果考虑字符串、单行注释里的块注释:
声明三个 regex:
r1 = //[^\n]*
r2 = "(?:\\.|[^\\"])*"
r3 = /\*[^*]*\*+(?:[*/*][^*]*\*+)*/
然后:s/($r2)|$r1|$r3/$1/g 意思是捕获双引号里的内容,放回去,其它的删掉
最终版
other = [^"/]
s/($other+|$r2$other*)|$r1|$r3/$1/g
这样会很快,1.$other+占大多数,会被优先匹配 2.$other*会加速引擎的判断,把不符合要求的部分跳过