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()方法对变量进行预处理
原因是静态方法会临时创建一个Regex对象,用它来调用请求的方法,然后弃用这个对象。而静态方法每次调用,都必须重新检查正则表达式,所以存在效率缺陷
虽然默认情况下,.NET Framework做了缓存处理,但默认只缓存15个正则表达式,尽管可以通过
Regex.CacheSize = 123;
来调整,但这并不是解决效率问题的根本方法
2、不要在循环体中声明Regex对象
因为这样使用,每次都要重新创建对象,重新对正则表达式进行编译,大大降低效率
3、如果正则需要在循环中调用,且循环次数比较多,正则要先在循环体外预编译,RegexOptions.Compiled
预编译会延长编译时间,占用更多的内存,但会加速匹配过程。一般在数据源较大、正则复杂、频繁调用、循环中使用时,可以考虑进行预编译
当然,在多处调用,且调用频繁的情况下,可以考虑封装到assembly中
4、除非对源字符串的结构非常清楚,否则不要轻易使用.*?这种非贪婪模式,非贪婪模式(exp)*?以及量词的嵌套使用不当,会造成无限循环回溯,通常是正则效率陷阱的根源,尽量使用排除型字符组[^…]和否定的正向环视(?!exp)结合贪婪模式来实现
通常情况下, <.+?>是没有 <[^>]*>的效率高的
5、匹配失败不需要回溯的子表达式,用固化分组(?>…)加速失败过程,同时避免回溯
那么 <[^>]*>通常还可以通过固化分组的方式进行优化 <(?>[^>]*)>
所以下面这一部分代码
- C# code
-
for (int i = 0; i < str1.Count; i++) { tmp = new StringBuilder(str1[i]); if (Regex.Replace(tmp.ToString(), @"<.+?>", "").Length > 5) //可以替换为 Regex tagReg = new Regex(@"<(?>[^>]*)>", RegexOptions.Compiled); for (int i = 0; i < str1.Count; i++) { tmp = new StringBuilder(str1[i]); if (tagReg.Replace(tmp.ToString(), "").Length > 5)
6、以“|”取“或”的分支结构,对效率的影响也很大,所以通常情况下,使用分支结构时,要尽可能的抽象出相同的规律,对分支的复杂度加以简化
- C# code
-
(<a .+?</a>)|(<pre(>|\s).+?</pre>) //可以简化为 <(a|pre)\b(?:(?!</?\1).)*</\1>
7、在循环中使用,当捕获组没有必须使用的理由时,使用非捕获组代替
捕获组匹配成功后,会将匹配的内容保存到一个组里,供以后引用,所以无意义的捕获组,会占用内存,降低效率
所以循环体中
- C# code
-
reg2 = new Regex(@"((^|>)[^<]+?)(" + _tag + ")", RegexOptions.IgnoreCase); //以及其后的一行 tmp.Insert(mat2.Index, mat2.Groups[1].Value + "<a href='/tag/" + mat2.Groups[2].Value + ".htm'>" + mat2.Groups[2].Value + "</a>"); //可以替换为 reg2 = new Regex(@"(?<=(?:^|>)(?:(?!" + _tag + ").)*)" + _tag , RegexOptions.IgnoreCase); tmp.Insert(mat2.Index, "<a href='/tag/" + mat2.Value + ".htm'>" + mat2.Value + "</a>");
受限于楼主的实现思路,reg2这个正则,必须是动态生成的,所以没有办法提取到循环体外,此处对性能的影响较大
8、另外,在.NET中动态生成正则表达式时,为了避免存在变量中有正则中具体特殊意义的字符,而导致正则解析失败,抛异常的问题,可以用Regex.Escape()方法对变量进行预处理
- C# code
-
reg2 = new Regex(@"(?<=(?:^|>)(?:(?!" + Regex.Escape(_tag) + ").)*)" + Regex.Escape(_tag) , RegexOptions.IgnoreCase);