zoukankan      html  css  js  c++  java
  • Regex.Replace 方法的性能!(090625最新修改)


     Regex.Replace 方法的性能!


        园子里有很多关于去除Html标签的文章。一个常用的经验是使用 Regex.Replace 方法利用正则去替换。这里有一篇使用该方法的文章 C#中如何去除HTML标记 。下面我贴出该方法的代码,见代码清单1-1

    代码清单1-1 引用 http://www.cnblogs.com/zoupeiyang/archive/2009/06/22/1508039.html       

            /// <summary>
            
    /// 去除HTML标记
            
    /// </summary>
            
    /// <param name="Htmlstring">包括HTML的源码 </param>
            
    /// <returns>已经去除后的文字</returns>
            public static string ReplaceHtmlTag(string Htmlstring)
            {
                
    //删除脚本
                Htmlstring = Htmlstring.Replace("\r\n""");
                Htmlstring 
    = Regex.Replace(Htmlstring, @"<script.*?</script>""", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"<style.*?</style>""", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"<.*?>""", RegexOptions.IgnoreCase);
                
    //删除HTML
                Htmlstring = Regex.Replace(Htmlstring, @"<(.[^>]*)>""", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"([\r\n])[\s]+""", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"-->""", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"<!--.*""", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"&(quot|#34);""\"", RegexOptions.IgnoreCase);
                Htmlstring = Regex.Replace(Htmlstring, @"&(amp|#38);""&", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"&(lt|#60);""<", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"&(gt|#62);"">", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"&(nbsp|#160);""", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"&(iexcl|#161);""\xa1", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"&(cent|#162);""\xa2", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"&(pound|#163);""\xa3", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"&(copy|#169);""\xa9", RegexOptions.IgnoreCase);
                Htmlstring 
    = Regex.Replace(Htmlstring, @"&#(\d+);""", RegexOptions.IgnoreCase);
                Htmlstring 
    = Htmlstring.Replace("<""");
                Htmlstring 
    = Htmlstring.Replace(">""");
                Htmlstring 
    = Htmlstring.Replace("\r\n""");
                
    return Htmlstring;
            }

        ReplaceHtmlTag方法内部使用了 Regex 类的静态方法来替换Html标签, Regex.Replace 方法见代码清单1-2

    代码清单1-2 

    public static string Replace (
        
    string input, // 要修改的字符串
        
    string pattern, //要匹配的正则表达式模式
        
    string replacement, //替换字符串
        RegexOptions options //RegexOption 枚举值的按位“或”组合
    ) // 返回已修改的字符串

        用 Reflector 打开System.dll ,在 System.Text.RegularExpressions 命名空间中找到 Regex 类。查看 代码清单1-2中 方法的实现,见代码清单1-3

    代码清单1-3

    public static string Replace(string input, string pattern, string replacement, RegexOptions options)
    {
        
    return new Regex(pattern, options, true).Replace(input, replacement);
    }

        很清楚的看到,该静态方法的内部实现是 实例化了一个 Regex 对象,并调用该对象的一个实例方法。该实例方法见 代码清单1-4

    代码清单1-4 

    public string Replace(string input, string replacement)
    {
        
    if (input == null)
        {
            
    throw new ArgumentNullException("input");
        }
        
    return this.Replace(input, replacement, -1this.UseOptionR() ? input.Length : 0);

        上面的代码在其内部实现上调用了另一个实例方法。该方法见代码清单1-5

    代码清单1-5

    public string Replace(string input, string replacement, int count, int startat)
    {
        
    if (input == null)
        {
            
    throw new ArgumentNullException("input");
        }
        
    if (replacement == null)
        {
            
    throw new ArgumentNullException("replacement");
        }
        RegexReplacement replacement2 
    = (RegexReplacement) this.replref.Get();
        
    if ((replacement2 == null|| !replacement2.Pattern.Equals(replacement))
        {
            replacement2 
    = RegexParser.ParseReplacement(replacement, this.caps, this.capsize, this.capnames, this.roptions);
            
    this.replref.Cache(replacement2);
        }
        
    return replacement2.Replace(this, input, count, startat);
    }

        重新查看代码清单1-1中的代码,一共调用了 Regex 类的 Replace 方法17次。从代码清单1-3中可以看出,执行代码清单1-1中的ReplaceHtmlTag 方法需要实例化 17个 Regex 对象。如果考虑一个应用在执行一次时需要调用 ReplaceHtmlTag 方法100次,那么就会在内存中实例化 17*100 个对象。如果 Regex.Replace 方法处理的字符串比较小,那么大多数的时间会花费在创建一个新的Regex对象的开销上。这样做显然是不值得的。那有什么方法可以避免不用实例化这么多的对象吗?

        首先我们得把代码1-2中的静态 Replace 方法替换成代码1-5中的实例 Replace 方法。但是调用 1-5中的实例方法时需要创建一个 Regex 对象。那结果不还是需要创建17个对象吗?对,这里确实是需要再创建17个对象,但我们可以利用单件模式把对象的创建工作封装在一个 ReplaceHtml 类中。见代码清单1-6

    代码清单1-6

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Text.RegularExpressions;

    namespace RegexTestWin
    {
        
    public class ReplaceHtml
        {
            
    private IList<Regex> _regexs = new List<Regex>();
            
    private IList<string> _replacement = new List<string>();

            
    private static ReplaceHtml _replaceHtml = null;
            
    private static readonly object _object = new object();
            
    private ReplaceHtml() { }
            
    public static ReplaceHtml Instance
            {
                
    get
                {
                    
    if (_replaceHtml == null)
                    {
                        
    lock (_object)
                        {
                            
    if (_replaceHtml == null)
                            {
                                _replaceHtml 
    = SetInstance(new ReplaceHtml());
                            }
                        }
                    }
                    
    return _replaceHtml;
                }
            }        

            
    /// <summary>去除Html标签 </summary>
            public string ReplaceHtmlTag(string Htmlstring)
            {
                Htmlstring 
    = Htmlstring.Replace("\r\n""");
                Regex aRegex 
    = null;
                
    for (int count = 0; count < this._replacement.Count; count++)
                {
                    aRegex 
    = this._regexs[count];
                    
    if (aRegex != null)
                    {
                        Htmlstring 
    = aRegex.Replace(Htmlstring, this._replacement[count], -10);
                    }
                }
                Htmlstring 
    = Htmlstring.Replace("<""");
                Htmlstring 
    = Htmlstring.Replace(">""");
                Htmlstring 
    = Htmlstring.Replace("\r\n""");
                
    return Htmlstring;
            }

            
    /// <summary>设置ReplaceHtml的Regex对象 </summary>
            private static ReplaceHtml SetInstance(ReplaceHtml aReplaceHtml)
            {
                
    #region 赋值正则表达式和替换后的字符数组
                
    string[] pattern = new string[]
                {
                    
    @"<script.*?</script>",@"<style.*?</style>",@"<.*?>",
                    
    @"<(.[^>]*)>",@"([\r\n])[\s]+",@"-->",
                    
    @"<!--.*",@"&(quot|#34);",@"&(amp|#38);",
                    
    @"&(lt|#60);",@"&(gt|#62);",@"&(nbsp|#160);",
                    
    @"&(iexcl|#161);",@"&(cent|#162);",@"&(pound|#163);",
                    
    @"&(copy|#169);",@"&#(\d+);"
                };
                
    string[] replacement = new string[]
                {
                    
    "","","","","","","","\"","&","<",">","","\xa1","\xa2","\xa3","\xa9",""
                };
                
    #endregion

                
    if (pattern.Length != replacement.Length)
                {
                    
    throw new Exception("正则表达式数组和替换后的字符数组的长度不一致!");
                }

                
    int count = 0//计数器
                foreach (string str in pattern)
                {
                    Regex aRegex 
    = new Regex(str,RegexOptions.IgnoreCase); //Edit By Old At 2009-06-25
                    aReplaceHtml.AddRegex(aRegex, replacement[count]);
                    count 
    += 1;
                }
                
    return aReplaceHtml;
            }

            
    /// <summary>
            
    /// 增加一个Regex对象
            
    /// </summary>
            
    /// <param name="aRegex">Regex 对象</param>
            
    /// <param name="Replacement">该对象对应的替换字符串</param>
            private void AddRegex(Regex aRegex, string Replacement)
            {
                _regexs.Add(aRegex);
                _replacement.Add(Replacement);
            }
            
        }
    }

        该类的使用如下,见代码清单1-7

    代码清单1-7

       public static string ReplaceHtmlTag2(string Htmlstring)
       {
           
    return ReplaceHtml.Instance.ReplaceHtmlTag(Htmlstring);
       }

        写到这里让我们来测试一下,2种方法在性能的差距。经过测试,在重复执行 ReplaceHtmlTag 方法和ReplaceHtmlTag2 方法 10,100,1000 次后,性能相差在 2-15陪左右。具体见图1-1

     

     图1-1 2种方法执行 1000 次所消耗的时间对比

        说明:该方法在处理短字符串时,性能差距很大。我用新浪的首页做过测试,2种方法的性能只相差1倍。附上源代码,感兴趣的读者可自行测试!:-)

    090625修正    代码清单1-6 中 private static ReplaceHtml SetInstance(ReplaceHtml aReplaceHtml) 这个方法的实现中,在构造Regex 对象时使用了 public Regex(string pattern) 这个构造函数,忘记了加上 RegexOptions.IgnoreCase 这个枚举。如果想准确的比较2者的性能,需要把 Regex 的构造函数换成带有枚举参数的构造函数。具体修改见代码清单1-6 ,修改后的性能没有上面提到的能达到 15 陪之多,只能提高在 2-5 陪。特此更正!

        这里下载:  RegexTest.rar

       End. 

  • 相关阅读:
    21.满足条件的01序列 卡特兰数
    20.求组合数 IV
    19.求组合数 III
    18.求组合数 II
    17.求组合数 I
    14.表达整数的奇怪方式 中国剩余定理 --------待复习标志--------
    16.高斯消元解异或线性方程组
    15.高斯消元解线性方程组
    writing: improvised lecture
    writing: a lesson about coronavirus epidemic
  • 原文地址:https://www.cnblogs.com/bruceleeliya/p/1509520.html
Copyright © 2011-2022 走看看