正则表达式
一、是什么?
就是一个概念,不同语言有不同的实现。
就是一个公式,使用一些特定的“元字符”来检索、匹配、替换符合规则的字符串。
元字符,如普通字符、标准字符、限定字符、定位字符等
二、正则表达式 引擎
工作流程:程序对“公式”进行语法分析,并建立语法分析树。根据语法分析树 结合 正则表达式的引擎生成 执行程序(这个执行程序,叫做状态机/自动机),用于字符串匹配。
正则表达式引擎,就是一套核心算法,用于建立状态机。
状态机的分类(编程语言中的正则表达式库,都是基于NFA实现的。)
DFA自动机(Deterministic Final Automata 确定有限状态自动机)
缺点:构造代价高
优点:效率快。若字符串长度是n,则匹配时间复杂度O(n)
NFA自动机(Non Deterministic Final Automata 非确定有限状态自动机)
优点:构造代价低
支持高级功能(如捕获group、环视、占有优先量),高级功能都是基于子表达式独立进行匹配。
缺点:效率慢(匹配过程存在 分支、回溯)。若字符串长度是n,且状态数为s,则匹配时间复杂度O(ns)。
原理
匹配流程?
存在问题?回溯。源于,贪婪特性
避免 回溯?公式中使用+、?、*、{min,max}等时,不同模式的处理方式不同
1、贪婪模式 Greedy。最大限度匹配更多内容,且回溯
text=“abbc”
regex=“ab{1,3}c” //匹配3个b
2、懒惰模式 Reluctant。尽可能少的匹配,避免回溯。通过?开启。
text=“abc”
regex=“ab{1,3}?c” //匹配1个b
3、独占模式 Posssessive。最大限度匹配更多的内容,但不回溯。通过+开启。
text=“abbc”
regex=“ab{1,3}+bc”
避免回溯?开启懒惰模式、或独占模式
三、正则表达式的优化
1、少用贪婪模式,多用独占模式
避免回溯
2、减少分支选择
1)考虑顺序。常用选项放前面,快速匹配
2)提取公共部分。(abcd|abef)替换为ab(cd|ef)。优先匹配ab,若无则放弃。
3)简单分支用index。三次index效率可能优于(X|Y|Z)
3、减少捕获嵌套
捕获组,正则表达式中,子表达式参与匹配,并将匹配的结果放入数字编号/显示命名的数组中,方便后面使用。一个()就是一个捕获组,支持嵌套。
例子//编号0,代表匹配的整个内容
String reg = "(<input.*?>)(.*?)(</input>)";
非捕获组,参与匹配,不获取某分组的内容。表达式一般为 (?:exp)
例子//用(?:X) 代替 (X)
String reg = "(?:<input.*?>)(.*?)(?:</input>)";
应用场景:如,注册页面中手机号校验、邮箱校验
总结,尽可能不用正则表达式,除非你已经做好性能排查。
任何一个细节问题,都有可能导致性能问题,根本原因是我们对这项技术的了解不够透彻。掌握方法论,学会透过现象看本质。