艾伟_转载: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:43

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

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

昨天有朋友写了一篇文章,其中比较了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框架的代码 既然是比较实现的区别,那么阅读代

艾伟: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的源码        

艾伟_转载:扩展方法 之 基本数据篇

前一篇我列举了几个最常用到的基于Asp.Net的扩展方法,而这一篇基于基本数据的扩展方法理应不会逊一筹,因为它不局限于Asp.Net.何谓基本数据,这里直接摆定义: C# 中有两种基本数据类型:值类型和引用类型. 值类型包括:简单类型.结构类型.枚举类型:引用类型包括:Object 类型.类类型.接口.代表元.字符串类型.数组. 说白了这篇就是扩展 int, string, double, DateTime...等基本类型.这么多数据类型,如果int来个扩展,double也来个扩展,肯定会是一个

艾伟_转载:虚方法的使用

<编程絮语>之一 C#的语法脱胎于C++,因而保留了virtual关键字,可以定义一个虚方法(或虚属性).一个类的成员被定义为virtual,就意味着它在告诉自己的子类:我准备了一笔遗产,你可以全盘接受,也可以完全拒绝或者修改我的遗嘱.显然,虚方法授予子类的权利甚至大于抽象方法.子类面对抽象方法只有重写(override)的权利,而对于虚方法,它还可以选择完全继承. 毫无疑问,虚方法破坏了对象的封装性.如果不加约束的使用,会对调用方造成破坏,至少它有可能破坏子类与父类之间在外在行为上的一致性.

艾伟_转载:扩展方法 之 Redirect 篇

前言: 单看标题,可能很多朋友不知道我到底想写什么.在写这篇文章前,我自己跟自己斗争了很久,到底该不该写这篇文章?毕竟从现实主义来看,这篇文章可能落入"瞎扯淡"的行列,因为对大多数朋友来说,以下的所有扩展方法可能都不会用到. 如果真是这样,就当作一个"漫无边际"的想法来看好了.如果你根本不想浪费你的宝贵时间,就点这里 Redirect 回博客园主页,呵呵 一个 Redirect 为什么也可以耗费一篇文章的笔墨? 就 Redirect 一词成文的先例估计不会是我,但如

艾伟_转载:老赵谈IL(3):IL可以看到的东西,其实大都也可以用C#来发现

在上一篇文章中,我们通过一些示例谈论了IL与CLR中的一些特性.IL与C#等高级语言的作用类似,主要用于表示程序的逻辑.由于它同样了解太多CLR中的高级特性,因此它在大部分情况下依旧无法展现出比那些高级语言更多的CLR细节.因此,如果您想要通过学习IL来了解CLR,那么这个过程很可能会"事倍功半".因此,从这个角度来说,老赵并不倾向于学习IL.不过严格说来,即使IL无法看出CLR的细节,也不足以说明"IL无用"--这里说"无用"自然有些夸张.但是

艾伟_转载:正则表达式30分钟入门教程

  本文目标 30分钟内让你明白正则表达式是什么,并对它有一些基本的了解,让你可以在自己的程序或网页里使用它. 如何使用本教程 最重要的是--请给我30分钟,如果你没有使用正则表达式的经验,请不要试图在30秒内入门--除非你是超人 :) 别被下面那些复杂的表达式吓倒,只要跟着我一步一步来,你会发现正则表达式其实并没有你想像中的那么困难.当然,如果你看完了这篇教程之后,发现自己明白了很多,却又几乎什么都记不得,那也是很正常的--我认为,没接触过正则表达式的人在看完这篇教程后,能把提到过的语法记住8