替换关键字 程序到优化

来源:互联网 发布:app软件开发培训 编辑:程序博客网 时间:2024/04/30 23:49

思想:
对一篇文章查找搜索关键字,并进行替换,变成链接形式

要求:
1、标签内的内容不参与替换,比如:<p title="关键字"> 虽然含有关键字,但不进行替换
2、本身是链接的内容不参与替换,如:<a>关键字</a>
3、<pre></pre>标签内的内容不参与替换,如:<pre>关键字</pre>
3、尽量做到一个关键字在一篇文章中只有一个被替换成链接(因为关键字很多,都替换成链接,整篇文章十分不雅)

 

 

 

 

 

 

结果是比较满意,可有一个严重的问题——速度太慢
 更改一下思路

 

 思路, 思路和.NET中一些使用正则需要注意的地方

因为是关键字替换,而关键字的数量也很多,所以从整体上来说有两种实现方式:
一种是在最外层循环关键字,每次替换一个符合条件的关键字,这样每循环一次,就要遍历一次源字符串
另一种是分次找出符合替换条件的子字符串,然后循环关键字进行替换,这样每次处理的源字符串相对较小,但关键字要遍历一次
因为相对于源字符串来说,关键字要小得多,所以一般来说还是后一种效率会高些
按楼主需求的前三条
1、标签内的内容不参与替换,比如: <p title="关键字"> 虽然含有关键字,但不进行替换 
2、本身是链接的内容不参与替换,如: <a>关键字 </a> 
3、 <pre> </pre>标签内的内容不参与替换,如: <pre>关键字 </pre> 
楼主所要替换的关键字,都是在不符合这三条的子字符串中,那就想办法先取出排除了这三种情况的子串,这时候子串中所包含的关键字就是可以替换的了
因为不符合替换需求的条件只有三条,所以一个正则表达式还是可以做到的
取出排除以上三种情况的子串,采用委托方式进行替换
因为楼主的第四个需求
3、尽量做到一个关键字在一篇文章中只有一个被替换成链接(因为关键字很多,都替换成链接,整篇文章十分不雅)
一个关键字只替换一次,那问题就好办了,只要执行过一次替换的关键字,就从关键字列表中去掉,这样不但可以满足楼主的要求,还可以减少每轮循环的次数

再讨论一下楼主的思路和.NET中一些使用正则需要注意的地方吧
可能楼主并不清楚正则中委托的应用,或者是不知道如何通过一个正则,来提取出排除了前三个条件的子串
所以楼主采用了先截取,再拼接的方式,其实跟委托的实现原理基本上是差不多的,只是没有委托这种实现方式效率高而已
再说一下楼主在正则使用中存在的问题吧,涉及到性能问题的时候,需要注意以下几个方面

1、不要使用静态方法,而一定要显式的声明Regex对象
原因是静态方法会临时创建一个Regex对象,用它来调用请求的方法,然后弃用这个对象。而静态方法每次调用,都必须重新检查正则表达式,所以存在效率缺陷 
虽然默认情况下,.NET Framework做了缓存处理,但默认只缓存15个正则表达式,尽管可以通过 
Regex.CacheSize = 123; 
来调整,但这并不是解决效率问题的根本方法

2、不要在循环体中声明Regex对象
因为这样使用,每次都要重新创建对象,重新对正则表达式进行编译,大大降低效率

3、如果正则需要在循环中调用,且循环次数比较多,正则要先在循环体外预编译,RegexOptions.Compiled  
预编译会延长编译时间,占用更多的内存,但会加速匹配过程。一般在数据源较大、正则复杂、频繁调用、循环中使用时,可以考虑进行预编译 
当然,在多处调用,且调用频繁的情况下,可以考虑封装到assembly中 

4、除非对源字符串的结构非常清楚,否则不要轻易使用.*?这种非贪婪模式,非贪婪模式(exp)*?以及量词的嵌套使用不当,会造成无限循环回溯,通常是正则效率陷阱的根源,尽量使用排除型字符组[^…]和否定的正向环视(?!exp)结合贪婪模式来实现
通常情况下,<.+?>是没有<[^>]*>的效率高的

5、匹配失败不需要回溯的子表达式,用固化分组(?>…)加速失败过程,同时避免回溯
那么<[^>]*>通常还可以通过固化分组的方式进行优化<(?>[^>]*)>

所以下面这一部分代码

 







6、以“|”取“或”的分支结构,对效率的影响也很大,所以通常情况下,使用分支结构时,要尽可能的抽象出相同的规律,对分支的复杂度加以简化


7、在循环中使用,当捕获组没有必须使用的理由时,使用非捕获组代替 
捕获组匹配成功后,会将匹配的内容保存到一个组里,供以后引用,所以无意义的捕获组,会占用内存,降低效率 

所以循环体中

 


受限于楼主的实现思路,reg2这个正则,必须是动态生成的,所以没有办法提取到循环体外,此处对性能的影响较大

8、另外,在.NET中动态生成正则表达式时,为了避免存在变量中有正则中具体特殊意义的字符,而导致正则解析失败,抛异常的问题,可以用Regex.Escape()方法对变量进行预处理

实现方式还是有优化空间的






http://www.appinn.com/regex/