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,  - 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  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],  - 1 0 );
                }
            }
            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. 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值