高性能正常匹配高效率提升
前言
写高性能正则匹配,有以下标准,这些标准是自己总结的:
1、使用正确的边界匹配器(^、$、b、B等)
2、应用具体的元字符和标识符类型(d、w、s等)
3、使用正确的量词( 、*、?、 ,m})
4、使用非捕捉组和分子组
5、注意量词的嵌入
其实很多正则匹配的优化技巧都是围绕“减少回朔”这样的原则进行改进的。、 ,m})
4、使用非捕捉组和分子组
5、注意量词的嵌入 其实很多正则匹配的优化技巧都是围绕“减少回朔”这样的原则进行改进的。
至于什么是“回朔”,小编就不在这里重复了,下面就根据具体的例子来了解这个过程。
实例1、以下是配对电子邮件地址的正则匹配:
^w ([.-]?w )*@w ([.-]?w )*(.w{2,3}) $
一步一步分析:
1、^w :表示需要标记符
逐渐, 而且是一个或多个;
2、([.-]?w )*里的“[.-]?表示配对“”.或“-”,零次或一次;
3、([.-]?w )*里的“w 还表示配对一个或多个字符;
4、([.-]?w )*所有这些都表示配对.xxx、-像xxx或xxx这样的字符,零次或多次;
5、第1-4步,配对sunny或sunny.yang这样的字符;
6、“@”是实际元,配对具体@; 7、 w :一个或多个字符也表示匹配,因为email不太可能这样做:sunny@.gmail.com;
8、 ([.-]?w )*:就像第2-4步一样,配对.163、-lib、.像gd这样的字符,零次或多次;
9、 (.w{2,3}) $:则配对.com、.cc那样末尾
而且由于w{2、3}限制了长度必须是2-3位,因此无法匹配.c、.n这样的字符。
乍一看,这样的分析整个过程没有问题,逻辑性恰到好处,但实际上隐藏了很多问题。看看下面的配对图,backtrack也表示回复(应用regexbudy可以清楚地看到这个过程)
整个成功匹配过程经历了55个步骤,首先,我们将分析整个配对过程:
1、配对图中的第1和2步^w ,匹配成功,匹配“admin”;
2、图中第三步,配对[.-]?,自然因为没有“自然”.“与“-”不匹配实际字符,而是因为“,自然因为没有“自然”.“与“-”不匹配实际字符,但由于“?”的限制,它可以匹配零或一次,所以子关系匹配是成功的,尽管它不匹配实际字符。
3、图4步,配对w ,因为“ “限制一个或多个标识符,但后续没有[a-zA-Z0-9]可以匹配,从而产生回朔,回溯到之前配对的成功位置,可能是admin;
4、图中第五步,因为上一步形成了回朔,所以“[.-]?w 因为匹配了零次([.-]?w )*中限零次或多次,因此配对成功,与实际字符不匹配;
配对过程的步骤如下:
^w ([.-]?w )*@w ([.-]?w )*(.w{2,3}) $
5、图中第6步与“@”相匹配 ,第七步匹配“w 也就是说,“匹配”open”;
6、图中第8-13步,配对“([.-]?w )*” ,匹配了“-lib、“.com”,配对“.com“可能不符合我们的期望,我们期望这种关系匹配是www.xx.gd.cn里的“.gd”;
7、图中第7-10步匹配open-lib,第7-13步匹配open-lib.com;
8、由于“([.-]?w )*“量词是“*”,然后继续重复这个过程;
9、 图中第14步配对“([.-]?w )*”里的“[.-]?因为此时此刻表针已经坐落在地上@open-lib.com之后,但由于量词“??因此,配对也取得了成功,但没有配对标识符,也没有配对标识符;
10、 图中第15步配对“([.-]?w )*”里的“w “此时,表针仍位于字符串数组的结尾,没有标志符可以匹配,因此匹配不成功,导致回复,返回成功位置,即图中的第13步,下一个表达匹配;
11、 图中第16步,配对(.w{2,3}) 里的.因为没有标识符可以配对,配对不成功,开展回朔;
12、图中第17步 ,(.w{2,3}) 中量词“ “,这意味着这种关系必须匹配一次或多次,因为最后一次匹配不成功,所以匹配零次,但不符合一次或多次的限制,所以再次回来;
二、下面看另一个同样配对邮箱地址的正则匹配:^w ([-.]w )*@w ([-.]w )*.w ([-.]w )*$
这种正则匹配看起来和上面的一样,但仔细观察是有区别的,一步一步地分析:
1、^w :表示需要标记符
逐渐, 而且是一个或多个(这一步和上面一样);
2、 ([-.]w )*里的“[-.]表示配对“-”或“-”.”;
3、 ([-.]w )*里的“w 还表示配对一个或多个字符;
4、([-.]w )*所有这些都表示配对.xxx、-xxx这样的字符,而零次或多次;
5、第1-4步,配对sunny或sunny.yang这样的字符;
6、“@”是实际元,配对具体“@”;
7、 w :一个或多个字符也表示匹配,因为email不太可能这样做:sunny@.gmail.com;
8、([-.]w )*:就像第2-4步一样,配对.163、-lib、.像gd这样的字符,零次或多次;
9“."是实际元,配对.”;
10、w :配对一个或多个标识符;
11、([-.]w )*:则配对“.com”、“-lib、“.c“这样的字符,可以零次或多次;
12、$ :也表示末尾乍一看,这个正则匹配的整个过程似乎比前一个过程长,但事实并非如此。同时,这种正则匹配也存在问题,先看配对图,同样的backtrack表示回朔:
正确的,你没听错,所有合适的匹配都在整个过程中使用19步骤,比较前面的
55步骤,真是天地之间的差异。,再分析一下配对的全过程:
1、配对图中的第1和2步^w ,匹配成功,匹配“admin”;
2、图中第三步,配对[-.],自然因为没有“自然”.“与“-”不匹配实际字符,
没有具体的量词可以配对零次,所以不需要再往下匹配,因此,回朔立即形成;
3、图中第四步,因为上一步形成了回朔,所以“[-.]w 因为匹配了零次([-.]w )*中限零次或多次,因此配对成功,与实际字符不匹配;
以下步骤,配对过程:
^w ([-.]w )*@w ([-.]w )*.w ([-.]w )*$
4、图中第6步w ,open匹配;
5、图中第7-12步配对([-.]w )*,匹配了“-lib”和“.com”;6、由于“([-.]w )*“量词是“*”,然后继续重复这个过程;
7、图13步,配对([-.]w )* ,因为这个时候表针已经坐落了@open-lib.com之后,
没有具体的量词可以配对零次,所以配对不成功,回到之前成功的位置;
8、图14步,配对 ([-.]w )*$里的“[-.]“此时,表针仍然位于字符串数组的结尾,没有任何标志符可以匹配,因此匹配不成功,导致回复和返回
之前成功过,还没试过位置,即图中第9步;
9、通过上面的回朔,表针已经坐落在那里了@open-lib之后的位置;
10、图15步匹配.”,第16步w 则匹配了“com” ;11、图第17步配对([-.]w )*,因为此时表针位于字符串数组的结尾,[-.]部分不匹配所有标识符,因此产生回朔;
12、图第18步,因为 ([-.]w )*量词为“*”,表示配对为零次,尽管子关系式[-.]配对不成功,所以整个关系匹配零次,都是配对成功;
13、在第19步的最后一步中,“$”表示结尾配对,因为此时表针位于字符串数组的结尾,所以配对也很成功。
剖析整个配对过程的重要改进区域,或回朔,两个例子的关系看起来相似,整个配对过程部分相似,但两个例子的效率如此之高,现在分析回朔的主要原因。剖析整个配对过程的重要改进区域,或回朔,两个例子的关系看起来相似,整个配对过程部分相似,但两个例子的效率如此之高,现在分析回朔的主要原因。比较两种不同类型关系类型的部分:^w ([.-]?w )*@w ([.-]?w )*(.w{2,3}) $