鸟食轩

 Microsoft .NET[C#] MVP 2003
随笔 - 429, 文章 - 235, 评论 - 5527, 引用 - 356
数据加载中……

忽略字符串大小写替换的更高效实现

    昨天灵感兄的一篇文章,其中仔细的比较了在.NET中做忽略字符串大小写替换的问题。并且给出了5个现有的解决方案,和详细的效率测试数据。不过仔细看完后,我对于Microsoft VisualBasic RunTime中的String.Replace的效率不敢苟同,特别是看过C#改写的代码后,更是疑窦丛生

    觉得VBString.Replace()效率有问题的主要原因是,Split()再Join()这个操作会带来大量的String碎片,这对于托管系统来说,代价是很大的。而且字符串中替换频率越高,对性能的损耗也就越是明显,后面的测试示例中我们会看到这个问题的。所以我实现的这个ReplaceEx()出发点就是避免产生String碎片,同时实现代码也不复杂,如下:

private static string ReplaceEx(string original, string pattern, string replacement)
{
    
int count, position0, position1;
    count 
= position0 = position1 = 0;
    
string upperString = original.ToUpper();
    
string upperPattern = pattern.ToUpper();
    
int inc = (original.Length/pattern.Length)*(replacement.Length-pattern.Length);
    
char [] chars = new char[original.Length + Math.Max(0, inc)];
    
while( (position1 = upperString.IndexOf(upperPattern, position0)) != -1 )
    
{
        
for ( int i=position0 ; i < position1 ; ++i ) chars[count++= original[i];
        
for ( int i=0 ; i < replacement.Length ; ++i ) chars[count++= replacement[i];
        position0 
= position1+pattern.Length;
    }

    
if ( position0 == 0 ) return original;
    
for ( int i=position0 ; i < original.Length ; ++i ) chars[count++= original[i];
    
return new string(chars, 0, count);
}

    只有18行代码,要说复杂大家也不会同意吧

    为了省事,直接用灵感兄的测试代码。他的Test Case是:"要把字符串"中华aBc共和国"中的"abc"替换为"人民",注意:源子字符串是"aBc",要替换的是"abc",这里目的是要测试不区分大小写。为了测试效率,我特意先把测试字符串累加1000次,然后循环测试1000次。"。

    测试数据如下: 
   
regexp
vb
vbReplace
ReplaceEx
Replace
= 2.05845295980355s
= 0.684810220293361s
= 0.679955692692786s
= 0.535100131441287s Fastest!
= 0.0564451627231953s (直接用的String.Replace(),仅做参考用)

    // .NET Framework 1.1, Windows xp sp2 en, P4 2.4G 512M.

    由于substring和substringB太慢了,我都没有耐心等待其结果了,故取消了对他们的测试。前面我提到说,如果被替换字符串的替换频率增大,vb和vbReplace这两个方法的开销也会急剧增大。下面看我的测试数据,不改变测试程序的循环次数,只修改:string segment = "中华aBc共和国";一句话。

    1、string segment = "中abc华aBc共和国";
   
regexp
vb
vbReplace
ReplaceEx
Replace
= 3.75481827997692s
= 1.52745502570857s
= 1.46234256029747s
= 0.797071415501132s !!!
= 0.178327413120941s

    // ReplaceEx > vbReplace > vb > regexp

    2、string segment = "中abc华aBc共abC和国";
   
regexp
vb
vbReplace
ReplaceEx
Replace
= 5.30117431126023s
= 2.46258449048692s
= 2.5018721653171s
= 1.00662179131705s !!!
= 0.233760994763301s

    // ReplaceEx > vb > vbReplace > regexp

    3、string segment = "中abc华aBc共abC和Abc国";
   
regexp
vb
vbReplace
ReplaceEx
Replace
= 7.00987862982586s
= 3.61050301085753s
= 3.42324876485699s
= 1.14969947297771s !!!
= 0.277254511397398s

    // ReplaceEx > vbReplace > vb > regexp

    4、string segment = "ABCabcAbCaBcAbcabCABCAbcaBC";
   
regexp
vb
vbReplace
ReplaceEx
Replace
= 13.5940090151123s
= 11.6806222578568s
= 11.1757614445411s
= 1.70264153684337s !!!(压倒优势)
= 0.42236820601501s

    // ReplaceEx > vbReplace > vb > regexp

    看到这里,是不是觉得ReplaceEx就是无敌的快了呢?其实我也希望是,不过在极端的情况下,就是segment中没有可以替换的pattern时,ReplaceEx就不行了:(

    5、string segment = "AaBbCc";
   
regexp
vb
vbReplace
ReplaceEx
Replace
= 0.671307945562914s
= 0.32356849823092s
= 0.316965703741677s !!!
= 0.418256510254795s
= 0.0453026851178013s

    // vbReplace > vb > ReplaceEx > regexp

    在第5个测试中,ReplaceEx效率不高的原因是,其所有消耗都耗费在了这两个语句上:

 string upperString = original.ToUpper();
 
string upperPattern = pattern.ToUpper();

    如果我们使用CompareInfo和CompareOptions来进行IndexOf操作,虽然可以避免对字符串进行case转换,但是除测试5中的极端情况外,其他情况下效率都低于ReplaceEx目前的实现。

    欢迎您测试运行效率,并提供更优化方案:)

    BTW: 记录测试数据不用多次平均,但最好不要使用第一次编译后的运行结果。

posted on 2005-07-01 00:41 birdshome 阅读(3644) 评论(12)  编辑 收藏 网摘 所属分类: .NET技术开发相关

评论

#1楼    回复  引用  查看    

替换频率增加导致Split的变慢与我的估计相同。我早先研究过类似问题,上次是“从字符串中查找字符出现次数的方法和性能对比”。当时就发现string.Replace的性能相当高,而Split由于创建过多的额外字符串而严重影响性能。
2005-07-01 08:57 | Ninputer      

#2楼    回复  引用  查看    

SubString经无数次验证,为效率极低的方法,一定要慎用。
2005-07-01 09:00 | Ninputer      

#3楼 [楼主]   回复  引用  查看    

说明创建一个String的代价叠加起来还是比较恐怖的,而且大量的String碎片等待GC,又会再次给系统带来很大的负担。
2005-07-01 09:38 | birdshome      

#4楼    回复  引用  查看    

这么说直接用的String.Replace()的性能才是最高的吗?
2005-07-01 10:06 | 7798.cn      

#5楼 [楼主]   回复  引用  查看    

@7798.cn
String.Replace() C# version is case-sensitive @_@.
2005-07-01 10:08 | birdshome      

#6楼    回复  引用  查看    

一个想法,如果一个类似算法能显著减少ToUppder的次数,应该有助于性能提升。
2005-07-01 10:10 | Ninputer      

#7楼 [楼主]   回复  引用  查看    

@Ninputer
嗯,ToUpper的代价确实不小,不过我测试String.Replace()的时候弄错了,中午我再修改一下,把ToUpper的代价单独量化出来。
2005-07-01 10:24 | birdshome      

#8楼    回复  引用  查看    


2005-07-01 11:18 | 奋斗中的灵感之源      

#9楼 [楼主]   回复  引用  查看    

@Ninputer
我开始的测试中,把作为基准的String.Replace()[C#]弄错了:(
time = new HiPerfTimer();
time.Start();
for (int i = 0; i < count; i++)
{
    result = source.Replace(pattern.ToUpper(), destination);*

}

time.Stop();
Console.WriteLine(
"Replace   = " + time.Duration + "s");
GC.Collect();
只对pattern做了case转换,而没有转换source
 
     要测试ToUpper()方法的代价,可以用这两个方法来测试:
string source1 = source.ToLower();
string pattern1 = pattern.ToLower();
time 
= new HiPerfTimer();
time.Start();
for (int i = 0; i < count; i++)
{
    result 
= source1.Replace(pattern1, destination);
}

time.Stop();
Console.WriteLine(
"Replace   = " + time.Duration + "s");
GC.Collect();
     和
time = new HiPerfTimer();
time.Start();
for (int i = 0; i < count; i++)
{
    result 
= source.ToUpper().Replace(pattern.ToUpper(), destination);
}

time.Stop();
Console.WriteLine(
"Replace2  = " + time.Duration + "s");
GC.Collect();
2005-07-01 12:57 | birdshome      

#10楼 [楼主]   回复  引用  查看    

1、string segment = "中华aBc共和国";
Replace
Replace2
= 0.035712360090458s
= 0.291085319502898s

2、string segment = "中abc华aBc共和国";
Replace
Replace2
= 0.053041378163984s
= 0.436732322124739s
 
3、string segment = "中abc华aBc共ABC和国";
Replace
Replace2
= 0.063522319177437s
= 0.581903565956008s
 
4、string segment = "中abc华aBc共ABC和AbC国";
Replace
Replace2
= 0.075015679367070s
= 0.684648188526754s
 
5、string segment = "ABCabcAbCaBcAbcabCABCAbcaBC";
Replace
Replace2
= 0.121759050382102s
= 1.004799213307840s

// .NET Framework 1.1, Windows 2003 en, P4 2.4 1G
2005-07-01 13:08 | birdshome      

发表评论



姓名 [登录] [注册] 
主页
Email (仅博主可见) 
验证码 *  验证码看不清,换一张
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论   新用户注册   返回页首      

导航: 网站首页 社区 新闻 博问 闪存 网摘 招聘 .NET频道 知识库 找找看 Google站内搜索



China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
China-Pub 计算机绝版图书按需印刷服务

相关文章:

相关链接: