分享一个String Replace方法

在上一编 文章里分享了自定义实现一个高效的String Split方法,接下来同样分享一下String相关操作的函数Replace.通过反编译查看String的Replace方法是内置实现无法查看具体 实现源码,因此无法推断出String的Replace方法实现如何;不过出于好奇自己手动去实现一个对应的Replace函数,从测试情况来看其效率相对来说比String的Replace方法要好些.

测试描述

为了让测试更全面所以进行不同内容替换和处理的不同次数添加到测试中.

  • 测试用的String数据

Cache-Control:public, max-age=0

Content-Encoding:gzip

Content-Length:9480

Content-Type:text/html; charset=utf-8

Date:Wed, 31 Oct 2012 14:17:06 GMT

Expires:Wed, 31 Oct 2012 14:17:05 GMT

Last-Modified:Wed, 31 Oct 2012 14:17:05 GMT

P3P:CP=NON DSP COR ADM CUR DEV TAI OUR IND NAV PRE STA

P3P:CP=NON DSP COR ADM CUR DEV TAI OUR IND NAV PRE STA

Server:Microsoft-IIS/7.5

Set-Cookie:smark=Branch=default&IsProject=1; domain=.codeplex.com; expires=Fri, 31-Oct-2042 14:17:06 GMT; path=/

Vary:Accept-Encoding

X-AspNet-Version:4.0.30319

X-AspNetMvc-Version:4.0

X-Powered-By:ASP.NET

  • 测试相关方法

static void StringReplace(string value,string olddata,string newdata)
{
    for (int i = 0; i < count; i++)
    {
        value.Replace(olddata, newdata);
    }

}
static void StringExtendReplace(string value, string olddata, string newdata)
{
    for (int i = 0; i < count; i++)
    {
        StringExtend.Replace(value,olddata, newdata);
    }
}
  • 具体测试代码

static void Main(string[] args)
{
   
    value.Replace("1", "010");
    StringExtend.Replace(value, "1", "010");
    Console.SetOut(new System.IO.StreamWriter("test.txt"));

    count = 1;
    TestReplace(value, "1", "010");
    count = 10;
    TestReplace(value, "C", "010");
    count = 100;
    TestReplace(value, "W", "010");
    count = 1000;
    TestReplace(value, "A", "010");
    count = 10000;
    TestReplace(value, "0", "010");
    count = 100000;
    TestReplace(value, ":", "010");

    count = 1;
    TestReplace(value, "ASP.NET", "ASPX");
    count = 10;
    TestReplace(value, "2012", "2048");
    count = 100;
    TestReplace(value, "Wed", "MVC");
    count = 1000;
    TestReplace(value, "Content", "TESTOPQ");
    count = 10000;
    TestReplace(value, "ASP.NET", "ASPX");
    count = 100000;
    TestReplace(value, "OUR", "BBQ");
    Console.Out.Flush();
    Console.Read();

}
static void TestReplace(string value, string olddata, string newdata)
{
    Console.WriteLine("=========[Count:{0}\t ({1} To {2})]===============", count, olddata, newdata);
    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

    sw.Reset();
    sw.Start();
    StringExtendReplace(value, olddata, newdata);
    sw.Stop();
    Console.WriteLine("StringExtendReplace:\t{0}ms", sw.Elapsed.TotalMilliseconds);

    sw.Reset();
    sw.Start();
    StringReplace(value, olddata, newdata);
    sw.Stop();
    Console.WriteLine("StringReplace:\t\t{0}ms", sw.Elapsed.TotalMilliseconds);
    Console.WriteLine("");
}
  • 测试结果

=========[Count:1(1 To 010)]===============

StringExtendReplace:0.1728ms

StringReplace:0.1654ms

 

=========[Count:10(C To 010)]===============

StringExtendReplace:0.0538ms

StringReplace:0.1002ms

 

=========[Count:100(W To 010)]===============

StringExtendReplace:0.4561ms

StringReplace:0.9015ms

 

=========[Count:1000(A To 010)]===============

StringExtendReplace:5.4919ms

StringReplace:11.0184ms

 

=========[Count:10000(0 To 010)]===============

StringExtendReplace:52.7016ms

StringReplace:96.3369ms

 

=========[Count:100000(: To 010)]===============

StringExtendReplace:633.8311ms

StringReplace:1025.9258ms

 

=========[Count:1(ASP.NET To ASPX)]===============

StringExtendReplace:0.0067ms

StringReplace:0.0084ms

 

=========[Count:10(2012 To 2048)]===============

StringExtendReplace:0.0424ms

StringReplace:0.0889ms

 

=========[Count:100(Wed To MVC)]===============

StringExtendReplace:0.4074ms

StringReplace:0.8477ms

 

=========[Count:1000(Content To TESTOPQ)]===============

StringExtendReplace:4.5297ms

StringReplace:7.6571ms

 

=========[Count:10000(ASP.NET To ASPX)]===============

StringExtendReplace:43.2199ms

StringReplace:82.9951ms

 

=========[Count:100000(OUR To BBQ)]===============

StringExtendReplace:442.286ms

StringReplace:841.7506ms

 

方法源代码

[ThreadStatic]
        static char[] mTempChars;

        protected static char[] GetTempData()
        {
            if (mTempChars == null)
                mTempChars = new char[1024 * 64];
            return mTempChars;
        }

        public static string Replace(string value, string oldData, string newData)
        {
            char[] tmpchars = GetTempData();
            int newpostion = 0;
            int oldpostion = 0;
            int length = value.Length;
            int oldlength = oldData.Length;
            int newlength = newData.Length;
            int index = 0;
            int copylength = 0;
            bool eq = false;
            while (index < value.Length)
            {
                eq = true;
                for (int k = 0; k < oldlength; k++)
                {
                    if (value[index + k] != oldData[k])
                    {
                        eq = false;
                        break;
                    }

                }
                if (eq)
                {
                    copylength = index - oldpostion;
                    value.CopyTo(oldpostion, tmpchars, newpostion, copylength);
                    newpostion += copylength;
                    index += oldlength;
                    oldpostion = index;
                    newData.CopyTo(0, tmpchars, newpostion, newlength);
                    newpostion += newlength;

                }
                else
                {
                    index++;
                }
            }
            if (oldpostion < length)
            {
                copylength = index - oldpostion;
                value.CopyTo(oldpostion, tmpchars, newpostion, copylength);
                newpostion += copylength;
            }
            return new string(tmpchars, 0, newpostion);
        }

总结

通 过[ThreadStatic]来对每个线程分配一组Char[],从而达到最少Char[]的开销.细心的朋友应该会发现每个线程分析的char[]大 小为64k,换句话说这个方法替换后超过64k则会异常,不过也可以分析需要设置一个最大值.如果有需要也可以给函数添加不区分大小写替换

posted @ 2012-11-05 09:09  beetlex  阅读(4526)  评论(0编辑  收藏  举报