Replace方法與Regex的效能比較

來源:互聯網
上載者:User

今天做項目時遇到一個小需求:要將字串中的斷行符號符號替換成其它符號(比如"<br/>")。 考慮到不同的情況下,有些系統中是用\r\n作斷行符號符,有些僅用\n就代表斷行符號符了。以前都是用String類的Replace方法串連替換多次來處理的,今天突然想改為Regex一次性搞定,但又怕效能上消耗太大,於是寫了下面的測試代碼:

using System;using System.Diagnostics;namespace ConsoleApplication1{    class Program    {        static void Main(string[] args)        {            string a = "11111 \n 22222 \r 33333 \n\r 44444 \r\n 55555 \r 66666";            Console.Write(Replace(a) + "\n");            Console.Write(RegReplace(a, "(\r|\n)+", "*") + "\n\n");            Stopwatch sw = new Stopwatch();            int count = 50000;            int times = 5;            long result = 0;            for (int i = 0; i < times; i++)            {                result += Test(sw, count, a, false);            }            Console.Write("\n{0}次×{1}輪測試,[Replace]方法平均每輪速度:{2}\n", count, times, result / times);            Console.Write("\n");            result = 0;            for (int i = 0; i < times; i++)            {                result += Test(sw, count, a, true);            }            Console.Write("\n{0}次×{1}輪測試,[Regex]方法平均每輪速度:{2}\n", count, times, result / times);            Console.Read();        }        static string RegReplace(string strSrc, string strRegPattern, string strReplace)        {            return System.Text.RegularExpressions.Regex.Replace(strSrc, strRegPattern, strReplace);        }        static string Replace(string strSrc)        {            return strSrc.Replace("\r\n", "*").Replace("\n\r", "*").Replace("\n", "*").Replace("\r", "*");        }        static long Test(Stopwatch sw, int count, string a, bool useRegularExpressions)        {            int i = 0;            sw.Reset();            sw.Start();            for (i = 0; i < count; i++)            {                if (useRegularExpressions)                {                    RegReplace(a, "(\r|\n)+", "*");                }                else                {                    Replace(a);                }            }            sw.Stop();            Console.Write(sw.ElapsedMilliseconds + "\n");            return sw.ElapsedMilliseconds;        }    }}

輸出結果:

11111 * 22222 * 33333 * 44444 * 55555 * 66666
11111 * 22222 * 33333 * 44444 * 55555 * 66666

94
89
88
86
83

50000次×5輪測試,[Replace]方法平均每輪速度:88

333
327
321
327
332

50000次×5輪測試,[Regex]方法平均每輪速度:328

可以看出,Regex要慢一倍都不止,大概慢 328/88 =3.7倍 (當然改變字串的長度以及斷行符號符的數量與位置,結果又會有一些差異)

註:經 Edwin Liu 在回複中提醒,Regex編譯預熱後速度要快一點,今天把測試代碼改了下

using System;using System.Diagnostics;using System.Text.RegularExpressions;namespace ConsoleApplication1{    class Program    {        static void Main(string[] args)        {            Regex reg = new Regex("(\r|\n)+", RegexOptions.Compiled);            string a = "11111 \n 22222 \r 33333 \n\r 44444 \r\n 55555 \r 66666";            Console.Write(Replace(a) + "\n");            Console.Write(reg.Replace(a, "*") + "\n\n");            Stopwatch sw = new Stopwatch();            int count = 50000;            int times = 5;            long result = 0;            for (int i = 0; i < times; i++)            {                result += Test(sw, count, a, false);            }            Console.Write("\n{0}次×{1}輪測試,[Replace]方法平均每輪速度:{2}\n", count, times, result / times);            Console.Write("\n");            result = 0;            for (int i = 0; i < times; i++)            {                result += Test(sw, count, a, true);            }            Console.Write("\n{0}次×{1}輪測試,[Regex]方法平均每輪速度:{2}\n", count, times, result / times);            Console.Read();        }                static string Replace(string strSrc)        {            return strSrc.Replace("\r\n", "*").Replace("\n\r", "*").Replace("\n", "*").Replace("\r", "*");        }                static long Test(Stopwatch sw, int count, string a, bool useRegularExpressions)        {            int i = 0;            Regex reg = new Regex("(\r|\n)+", RegexOptions.Compiled);            sw.Reset();            sw.Start();            for (i = 0; i < count; i++)            {                if (useRegularExpressions)                {                                       reg.Replace(a, "*");                }                else                {                    Replace(a);                }            }            sw.Stop();            Console.Write(sw.ElapsedMilliseconds + "\n");            return sw.ElapsedMilliseconds;        }    }}

新的測試結果:

11111 * 22222 * 33333 * 44444 * 55555 * 66666
11111 * 22222 * 33333 * 44444 * 55555 * 66666

100
93
86
86
84

50000次×5輪測試,[Replace]方法平均每輪速度:89

204
200
201
210
190

50000次×5輪測試,[Regex]方法平均每輪速度:201

粗略比較一下:編譯預熱後 慢201/89=2.3倍,相當剛才的3.7倍確實有所提高,但是相對於String類的Replace方法仍然可以認為很慢。(不過從方便程度上講,有些複雜的功能用Regex還是很方便的)

二、Silverlight 4.0環境

註:Silverlight中沒有Stopwatch類,所以用DateTime.Now計時代替了,但這樣可能結果不太精確;另外silverlight中的Regex也沒有編譯預熱功能,所以只能用最原始的方法。

using System;using System.Diagnostics;using System.Windows;using System.Windows.Controls;using System.Text.RegularExpressions;namespace SilverlightApplication1{    public partial class MainPage : UserControl    {        public MainPage()        {            InitializeComponent();            this.Loaded += new RoutedEventHandler(MainPage_Loaded);        }        void MainPage_Loaded(object sender, RoutedEventArgs e)        {            string a = "11111 \n 22222 \r 33333 \n\r 44444 \r\n 55555 \r 66666";            Debug.WriteLine(Replace(a));            Debug.WriteLine(RegReplace(a, "(\r|\n)+", "*") + "\n");            int count = 50000;            int times = 5;            double result = 0;            for (int i = 0; i < times; i++)            {                result += Test(count, a, false);            }            Debug.WriteLine("{0}次×{1}輪測試,[Replace]方法平均每輪速度:{2}\n", count, times, result / times);            result = 0;            for (int i = 0; i < times; i++)            {                result += Test(count, a, true);            }            Debug.WriteLine("{0}次×{1}輪測試,[Regex]方法平均每輪速度:{2}\n", count, times, result / times);        }               string RegReplace(string strSrc, string strRegPattern, string strReplace)        {                       return System.Text.RegularExpressions.Regex.Replace(strSrc, strRegPattern, strReplace);        }               string Replace(string strSrc)        {            return strSrc.Replace("\r\n", "*").Replace("\n\r", "*").Replace("\n", "*").Replace("\r", "*");        }               double Test(int count, string a, bool useRegularExpressions)        {            int i = 0;            DateTime _start = DateTime.Now;            for (i = 0; i < count; i++)            {                if (useRegularExpressions)                {                    RegReplace(a, "(\r|\n)+", "*");                }                else                {                    Replace(a);                }            }            DateTime _end = DateTime.Now;            TimeSpan span = _end - _start;            Debug.WriteLine(span.TotalMilliseconds);            return span.TotalMilliseconds;        }    }}

輸出結果:

11111 * 22222 * 33333 * 44444 * 55555 * 66666
11111 * 22222 * 33333 * 44444 * 55555 * 66666

78.0002
93.6001
93.6002
78.0001
93.6002
50000次×5輪測試,[Replace]方法平均每輪速度:87.36016

405.6007
405.6007
483.6009
405.6007
405.6007
50000次×5輪測試,[Regex]方法平均每輪速度:421.20074

可以看出,基本上跟Console程式在一個數量級(因為底層的CLR基本上是差不多的,這也符合預期,但貌似Silverlight的Regex要慢一點,估計跟沒有編譯預熱功能有很大關係)

三、AS3.0的測試

註:前幾天看到園子裡有高手說AS3.0的效能大約是Silverlight的80%,很是好奇,所以最後也順便放到AS3.0中測試了一下,但要注意的是:因為ActionScript3.0中String的replace方法跟JS一樣,預設只能替換第一次找到的字串,所以基本上要實現全盤替換,只能用Regex

import flash.utils.Timer;function Replace(strSrc:String):String {var myPattern:RegExp = /\r|\n/gi; return strSrc.replace(myPattern,"*");}function Test(strSrc:String,count:uint):int {var i:uint=0;var _start=getTimer();for (i=0; i<count; i++) {Replace(strSrc);}var _end=getTimer();var elapsedTime=_end-_start;trace(elapsedTime);return elapsedTime;}var a:String="11111 \n 22222 \r 33333 \n\r 44444 \r\n 55555 \r 66666";trace(Replace(a));var count:uint=50000;var times:uint=5;var rlt:Number=0;for (var i:uint=0; i<times; i++) {rlt+=Test(a,count);}trace(count,"次×",times,"輪測試,[Replace]方法平均每輪速度:",rlt/times);

輸出結果:

11111 * 22222 * 33333 ** 44444 ** 55555 * 66666
1547
1508
1509
1515
1504
50000 次× 5 輪測試,[Replace]方法平均每輪速度: 1516.6

但這個結果就很誇張了。

註:今天早上又測試了好幾把,好象結果又快了一點,估計是昨天測試的時候有些程式沒關

11111 * 22222 * 33333 ** 44444 ** 55555 * 66666
1048
1002
1001
1000
1009
50000 次× 5 輪測試,[Replace]方法平均每輪速度: 1012
當然上面的樣本中,加了gi標誌,即全域尋找,並忽略大小寫,如果去掉大小寫標記,即var myPattern:RegExp = /\r|\n/gi; 改成 var myPattern:RegExp = /\r|\n/g; 速度能快一點

11111 * 22222 * 33333 ** 44444 ** 55555 * 66666
1015
971
972
970
971
50000 次× 5 輪測試,[Replace]方法平均每輪速度: 979.8

 

後記:本文的測試很是粗放,主要也就是看個大概,以便心中有個印象而已,歡迎高手做更精確的測試。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.