艾伟:Regex.Replace 方法的性能!

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

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

        /// 
        /// 去除HTML标记
        /// 
        /// 包括HTML的源码 
        /// 已经去除后的文字
        public static string ReplaceHtmlTag(string Htmlstring)
        {
            //删除脚本
            Htmlstring = Htmlstring.Replace("\r\n", "");
            Htmlstring = Regex.Replace(Htmlstring, @"", "", RegexOptions.IgnoreCase);
            Htmlstring = Regex.Replace(Htmlstring, @"
", "", 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, -1, this.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 IListRegex> _regexs = new ListRegex>();
        private IListstring> _replacement = new Liststring>();

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;
            }
        }

/// 

去除Html标签 

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], -1, 0);
                }
            }
            Htmlstring = Htmlstring.Replace("", "");
            Htmlstring = Htmlstring.Replace(">", "");
            Htmlstring = Htmlstring.Replace("\r\n", "");
            return Htmlstring;
        }

/// 

设置ReplaceHtml的Regex对象 

private static ReplaceHtml SetInstance(ReplaceHtml aReplaceHtml)
        {
            #region 赋值正则表达式和替换后的字符数组
            string[] pattern = new string[]
            {
                @"
",@"", "", 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, -1, this.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 IListRegex> _regexs = new ListRegex>();
        private IListstring> _replacement = new Liststring>();

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;
            }
        }

/// 

去除Html标签 

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], -1, 0);
                }
            }
            Htmlstring = Htmlstring.Replace("", "");
            Htmlstring = Htmlstring.Replace(">", "");
            Htmlstring = Htmlstring.Replace("\r\n", "");
            return Htmlstring;
        }

/// 

设置ReplaceHtml的Regex对象 

private static ReplaceHtml SetInstance(ReplaceHtml aReplaceHtml)
        {
            #region 赋值正则表达式和替换后的字符数组
            string[] pattern = new string[]
            {
                @"
",@"",@"<.*?>",
                @"<(.[^>]*)>",@"([\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);
                aReplaceHtml.AddRegex(aRegex, replacement[count]);
                count += 1;
            }
            return aReplaceHtml;
        }

        /// 
        /// 增加一个Regex对象
        /// 
        /// Regex 对象
        /// 该对象对应的替换字符串
        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倍。附上源代码,感兴趣的读者可自行测试!:-)

    这里下载:  RegexTest.rar

    End.

时间: 2024-10-23 15:17:49

艾伟:Regex.Replace 方法的性能!的相关文章

艾伟_转载:Regex.Replace 方法的性能!

    园子里有很多关于去除Html标签的文章.一个常用的经验是使用 Regex.Replace 方法利用正则去替换.这里有一篇使用该方法的文章 C#中如何去除HTML标记 .下面我贴出该方法的代码,见代码清单1-1 代码清单1-1 引用 http://www.cnblogs.com/zoupeiyang/archive/2009/06/22/1508039.html                ///          /// 去除HTML标记         ///          //

Regex.Replace 方法的性能!

园子里有很多关于去除Html标签的文章.一个常用的经验是使用 Regex.Replace 方法利用正则去替换.这里有一篇使用该方法的文章 C#中如何去除HTML标记 .下面我贴出该方法的代码,见代码清单1-1 代码清单1-1 引用 http://www.cnblogs.com/zoupeiyang/archive/2009/06/22/1508039.html ///          /// 去除HTML标记         ///          /// 包括HTML的源码        

Regex.Replace正则表达式替换问题

问题描述 Regex.Replace正则表达式替换问题 有一个字符串:10[?2] 我换把这个字符串用正则表达式Regex.Replace方法替换成: 102要怎么写? 解决方案 Regex.Replace(s, @"(d+)[?2]", "${1}" + "2"); 解决方案二: 你都知道要替换的内容了还有必要用正则嘛..

艾伟_转载:数组排序方法的性能比较(上):注意事项及试验

昨天有朋友写了一篇文章,其中比较了List的Sort方法与LINQ中排序方法的性能,而最终得到的结果是"LINQ排序方法性能高于List.Sort方法".这个结果不禁让我很疑惑.因为List.Sort方法是改变容器内部元素的顺序,而LINQ排序后得到的是一个新的序列.假如两个排序方法的算法完全一致,LINQ排序也比对方多出元素复制的开销,为什么性能反而会高?如果LINQ排序的算法/实现更为优秀,那为什么.NET Fx不将List.Sort也一并优化一下呢?于是今天我也对这个问题进行了简

艾伟_转载:数组排序方法的性能比较(中):Array.Sort&lt;T&gt; 实现分析

昨天我们比较了Array.Sort方法与LINQ排序的性能,知道了LINQ排序的性能以较大幅度落后于Array.Sort方法.而对于Array.Sort来说,性能最高的是其中使用Comparer.Default作为比较器的重载方法.在前文的末尾我们做出了推测:由于排序算法已经近乎一个标准了(快速排序),因此从算法角度来说,Array.Sort方法和LINQ排序上不应该有那么大的差距,因此造成两者性能差异的原因,应该是具体实现方式上的问题. 下载.NET框架的代码 既然是比较实现的区别,那么阅读代

如何使replace方法不区分大小写?

大小写 被替换的文本的实际模式是通过 RegExp 对象的 Pattern 属性设置的. Replace 方法返回 string1 的副本,其中的 RegExp.Pattern 文本已经被替换为 string2.如果没有找到匹配的文本,将返回原来的 string1 的副本. 下面的例子说明了 Replace 方法的用法. Function ReplaceTest(patrn, replStr)Dim regEx, str1 ' 建立变量.str1 = "The quick brown fox j

如何使replace方法不区分大小写

大小写 被替换的文本的实际模式是通过 RegExp 对象的 Pattern 属性设置的. Replace 方法返回 string1 的副本,其中的 RegExp.Pattern 文本已经被替换为 string2.如果没有找到匹配的文本,将 返回原来的 string1 的副本. 下面的例子说明了 Replace 方法的用法. Function ReplaceTest(patrn, replStr) Dim regEx, str1 ' 建立变量. str1 = "The quick brown fo

replace()方法查找字符使用示例_javascript技巧

通常用于文本输入框的一种功能是替换指定的字符.JavaScript具有一个非常有用的方法replace(),可以时候用它利用备选字符集途欢指定的字符. replace()方法允许指定希望替换的字符或字符集,方式是利用字符串或者正则表达式:这是该方法的第一个实参.第二个实参是谢昂替换为的字符.第二个实参通常只是一个替换字符串(替换字符集),但他可以是用于确定替换字符串应当是什么的函数--如果是函数,则返回值应当用做俄日替换字符串.隐藏replace()方法的语法可以是如下任意一种: 复制代码 代码

VBS教程:方法-Replace 方法_vbs

Replace 方法 替换在正则表达式查找中找到的文本. object.Replace(string1, string2) 参数 object 必选项.总是一个 RegExp 对象的名称. string1 必选项.string1 是将要进行文本替换的字符串. string2 必选项. string2 是替换文本字符串. 说明 被替换的文本的实际模式是通过 RegExp 对象的 Pattern 属性设置的. Replace 方法返回 string1 的副本,其中的 RegExp.Pattern 文