天天看點

忽略字元串大小寫替換的更高效實作

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共和國";

= 3.75481827997692s

= 1.52745502570857s

= 1.46234256029747s

= 0.797071415501132s !!!

= 0.178327413120941s

    // ReplaceEx > vbReplace > vb > regexp

    2、string segment = "中abc華aBc共abC和國";

= 5.30117431126023s

= 2.46258449048692s

= 2.5018721653171s

= 1.00662179131705s !!!

= 0.233760994763301s

    // ReplaceEx > vb > vbReplace > regexp

    3、string segment = "中abc華aBc共abC和Abc國";

= 7.00987862982586s

= 3.61050301085753s

= 3.42324876485699s

= 1.14969947297771s !!!

= 0.277254511397398s

    // ReplaceEx > vbReplace > vb > regexp

    4、string segment = "ABCabcAbCaBcAbcabCABCAbcaBC";

= 13.5940090151123s

= 11.6806222578568s

= 11.1757614445411s

= 1.70264153684337s !!!(壓倒優勢)

= 0.42236820601501s

    看到這裡,是不是覺得ReplaceEx就是無敵的快了呢?其實我也希望是,不過在極端的情況下,就是segment中沒有可以替換的pattern時,ReplaceEx就不行了:(

    5、string segment = "AaBbCc";

= 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: 記錄測試資料不用多次平均,但最好不要使用第一次編譯後的運作結果。

本文轉自部落格園鳥食軒的部落格,原文連結:http://www.cnblogs.com/birdshome/,如需轉載請自行聯系原部落客。

繼續閱讀