当前位置:  开发笔记 > 编程语言 > 正文

反转字符串的最佳方法

如何解决《反转字符串的最佳方法》经验,为你挑选了16个好方法。

我只需要在C#2.0中编写一个字符串反向函数(即LINQ不可用)并想出了这个:

public string Reverse(string text)
{
    char[] cArray = text.ToCharArray();
    string reverse = String.Empty;
    for (int i = cArray.Length - 1; i > -1; i--)
    {
        reverse += cArray[i];
    }
    return reverse;
}

就个人而言,我并不是对这个功能感到疯狂,并且我确信有更好的方法可以做到这一点.在那儿?



1> PeteT..:
public static string Reverse( string s )
{
    char[] charArray = s.ToCharArray();
    Array.Reverse( charArray );
    return new string( charArray );
}


@Arachnid:实际上,C#中的字符是UTF-16代码单元; 它需要两个代表一个补充字符.见http://www.jaggersoft.com/csharp_standard/9.4.1.htm.
Unicode控制字符使此方法对非拉丁字符集无用.请参阅Jon Skeet解释,使用袜子木偶:http://codeblog.jonskeet.uk/2009/11/02/omg-ponies-aka-humanity-epic-fail/(1/4向下),或视频:http://vimeo.com/7516539
希望您不会遇到任何代理人或组合人物.
sambo99:不需要提及unicode:C#中的字符是unicode字符,而不是字节.Xor可能更快,但除了可读性差外,甚至可能是Array.Reverse()内部使用的.
是的sambo99我想你是对的,但使用UTF-32是一种非常罕见的情况.并且XOR对于非常小的值范围来说速度更快,正确的答案是为不同的长度实现不同的方法我想.但这很简洁明了,这在我看来是有益的.

2> R. Martinho ..:

在这里,妥善反转字符串的解决方案"Les Mise\u0301rables""selbare\u0301siM seL".这应该呈现selbarésiM seL,不是selbar?esiM seL(注意重音的位置),大多数实现的结果都是基于代码单元(Array.Reverse等)或甚至代码点(特别注意代理对的反转).

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

public static class Test
{
    private static IEnumerable GraphemeClusters(this string s) {
        var enumerator = StringInfo.GetTextElementEnumerator(s);
        while(enumerator.MoveNext()) {
            yield return (string)enumerator.Current;
        }
    }
    private static string ReverseGraphemeClusters(this string s) {
        return string.Join("", s.GraphemeClusters().Reverse().ToArray());
    }

    public static void Main()
    {
        var s = "Les Mise\u0301rables";
        var r = s.ReverseGraphemeClusters();
        Console.WriteLine(r);
    }
}

(现场运行示例:https://ideone.com/DqAeMJ)

它只是使用.NET API进行字形集群迭代,它从那时起一直存在,但看起来有点"隐藏".


+1很少有正确的答案之一,****比其他任何人都更优雅和未来证明,IMO
很有趣的是,大多数其他的回答者都试图从其他不正确的方法中删除ms.如何代表.
实例化StringInfo实际上要快得多,然后遍历SubstringByTextElements(x,1)并使用StringBuilder构建一个新字符串.
您使用了乔恩·斯凯特(Jon Skeet)早些年给他的例子https://codeblog.jonskeet.uk/2009/11/02/omg-ponies-aka-humanity-epic-fail/ LesMisérables(尽管乔恩(Jon没有提及解决方案,他只是列出了问题)。很好,您想出了一个解决方案。也许乔恩·斯凯特(Jon skeet)发明了一种时光机,回到2009年,并发布了您在解决方案中使用的问题示例。

3> Sam Saffron..:

这结果是一个令人惊讶的棘手问题.

我建议在大多数情况下使用Array.Reverse,因为它是本地编码的,维护和理解非常简单.

在我测试的所有情况下,它似乎都优于StringBuilder.

public string Reverse(string text)
{
   if (text == null) return null;

   // this was posted by petebob as well 
   char[] array = text.ToCharArray();
   Array.Reverse(array);
   return new String(array);
}

对于使用Xor的某些字符串长度,有第二种方法可以更快.

    public static string ReverseXor(string s)
    {
        if (s == null) return null;
        char[] charArray = s.ToCharArray();
        int len = s.Length - 1;

        for (int i = 0; i < len; i++, len--)
        {
            charArray[i] ^= charArray[len];
            charArray[len] ^= charArray[i];
            charArray[i] ^= charArray[len];
        }

        return new string(charArray);
    }

注意如果要支持完整的Unicode UTF16字符集,请阅读此内容.而是使用那里的实现.它可以通过使用上述算法之一进行进一步优化,并在字符串反转后通过字符串进行清理.

这是StringBuilder,Array.Reverse和Xor方法之间的性能比较.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication4
{
    class Program
    {
        delegate string StringDelegate(string s);

        static void Benchmark(string description, StringDelegate d, int times, string text)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int j = 0; j < times; j++)
            {
                d(text);
            }
            sw.Stop();
            Console.WriteLine("{0} Ticks {1} : called {2} times.", sw.ElapsedTicks, description, times);
        }

        public static string ReverseXor(string s)
        {
            char[] charArray = s.ToCharArray();
            int len = s.Length - 1;

            for (int i = 0; i < len; i++, len--)
            {
                charArray[i] ^= charArray[len];
                charArray[len] ^= charArray[i];
                charArray[i] ^= charArray[len];
            }

            return new string(charArray);
        }

        public static string ReverseSB(string text)
        {
            StringBuilder builder = new StringBuilder(text.Length);
            for (int i = text.Length - 1; i >= 0; i--)
            {
                builder.Append(text[i]);
            }
            return builder.ToString();
        }

        public static string ReverseArray(string text)
        {
            char[] array = text.ToCharArray();
            Array.Reverse(array);
            return (new string(array));
        }

        public static string StringOfLength(int length)
        {
            Random random = new Random();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < length; i++)
            {
                sb.Append(Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))));
            }
            return sb.ToString();
        }

        static void Main(string[] args)
        {

            int[] lengths = new int[] {1,10,15,25,50,75,100,1000,100000};

            foreach (int l in lengths)
            {
                int iterations = 10000;
                string text = StringOfLength(l);
                Benchmark(String.Format("String Builder (Length: {0})", l), ReverseSB, iterations, text);
                Benchmark(String.Format("Array.Reverse (Length: {0})", l), ReverseArray, iterations, text);
                Benchmark(String.Format("Xor (Length: {0})", l), ReverseXor, iterations, text);

                Console.WriteLine();    
            }

            Console.Read();
        }
    }
}

结果如下:

26251 Ticks String Builder (Length: 1) : called 10000 times.
33373 Ticks Array.Reverse (Length: 1) : called 10000 times.
20162 Ticks Xor (Length: 1) : called 10000 times.

51321 Ticks String Builder (Length: 10) : called 10000 times.
37105 Ticks Array.Reverse (Length: 10) : called 10000 times.
23974 Ticks Xor (Length: 10) : called 10000 times.

66570 Ticks String Builder (Length: 15) : called 10000 times.
26027 Ticks Array.Reverse (Length: 15) : called 10000 times.
24017 Ticks Xor (Length: 15) : called 10000 times.

101609 Ticks String Builder (Length: 25) : called 10000 times.
28472 Ticks Array.Reverse (Length: 25) : called 10000 times.
35355 Ticks Xor (Length: 25) : called 10000 times.

161601 Ticks String Builder (Length: 50) : called 10000 times.
35839 Ticks Array.Reverse (Length: 50) : called 10000 times.
51185 Ticks Xor (Length: 50) : called 10000 times.

230898 Ticks String Builder (Length: 75) : called 10000 times.
40628 Ticks Array.Reverse (Length: 75) : called 10000 times.
78906 Ticks Xor (Length: 75) : called 10000 times.

312017 Ticks String Builder (Length: 100) : called 10000 times.
52225 Ticks Array.Reverse (Length: 100) : called 10000 times.
110195 Ticks Xor (Length: 100) : called 10000 times.

2970691 Ticks String Builder (Length: 1000) : called 10000 times.
292094 Ticks Array.Reverse (Length: 1000) : called 10000 times.
846585 Ticks Xor (Length: 1000) : called 10000 times.

305564115 Ticks String Builder (Length: 100000) : called 10000 times.
74884495 Ticks Array.Reverse (Length: 100000) : called 10000 times.
125409674 Ticks Xor (Length: 100000) : called 10000 times.

对于短字符串来说,Xor似乎更快.


这些方法不处理包含基本多语言平面之外的字符的字符串,即用两个C#字符表示的Unicode字符> = U + 10000.我发布了一个正确处理这些字符串的答案.
这不会返回一个字符串 - 你需要在调用"new String(...)"时将其包装起来

4> Bradley Grai..:

如果字符串包含Unicode数据(严格来说,非BMP字符),则已发布的其他方法将损坏它,因为在反转字符串时无法交换高和低代理代码单元的顺序.(有关此内容的更多信息,请访问我的博客.)

以下代码示例将正确反转包含非BMP字符的字符串,例如"\ U00010380\U00010381"(Ugaritic Letter Alpa,Ugaritic Letter Beta).

public static string Reverse(this string input)
{
    if (input == null)
        throw new ArgumentNullException("input");

    // allocate a buffer to hold the output
    char[] output = new char[input.Length];
    for (int outputIndex = 0, inputIndex = input.Length - 1; outputIndex < input.Length; outputIndex++, inputIndex--)
    {
        // check for surrogate pair
        if (input[inputIndex] >= 0xDC00 && input[inputIndex] <= 0xDFFF &&
            inputIndex > 0 && input[inputIndex - 1] >= 0xD800 && input[inputIndex - 1] <= 0xDBFF)
        {
            // preserve the order of the surrogate pair code units
            output[outputIndex + 1] = input[inputIndex];
            output[outputIndex] = input[inputIndex - 1];
            outputIndex++;
            inputIndex--;
        }
        else
        {
            output[outputIndex] = input[inputIndex];
        }
    }

    return new string(output);
}


实际上,C#中的字符是16位UTF-16代码单元; 补充字符使用其中两个编码,所以这是必要的,
看起来System.String实际上应该为包含Unicode补充字符的字符串公开HereBeDragons属性.
@SebastianNegraszus:这是正确的:这个方法只是反转字符串中的代码点.反转[字形集群](http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries)整体上可能会更"有用"(但是首先反转任意字符串的"用途"是什么?) ,但仅使用.NET Framework中的内置方法实现起来并不容易.
@Richard:打破字形集群的规则比检测组合代码点要复杂一些; 有关详细信息,请参阅UAX#29中有关[Grapheme Cluster Boundaries](http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries)的文档.

5> SGRao..:

来自3.5框架

public string ReverseString(string srtVarable)
{
    return new string(srtVarable.Reverse().ToArray());
}


这不是最快的解决方案,但作为单行有用。

6> richardtalle..:

好的,为了"不要重复自己",我提供了以下解决方案:

public string Reverse(string text)
{
   return Microsoft.VisualBasic.Strings.StrReverse(text);
}

我的理解是这个实现,默认情况下在VB.NET中可用,正确处理Unicode字符.


这只能正确处理代理人.它混淆了标记:http://ideone.com/yikdqX.

7> Dan Tao..:

Greg Beech发布的unsafe选项确实和它一样快(它是一个就地反转); 但是,正如他在回答中指出的那样,这是一个完全灾难性的想法.

也就是说,我很惊讶有很多共识Array.Reverse是最快的方法.还有一种unsafe方法可以返回字符串的反向副本(没有就地反转恶作剧),比Array.Reverse小字符串方法快得多:

public static unsafe string Reverse(string text)
{
    int len = text.Length;

    // Why allocate a char[] array on the heap when you won't use it
    // outside of this method? Use the stack.
    char* reversed = stackalloc char[len];

    // Avoid bounds-checking performance penalties.
    fixed (char* str = text)
    {
        int i = 0;
        int j = i + len - 1;
        while (i < len)
        {
            reversed[i++] = str[j--];
        }
    }

    // Need to use this overload for the System.String constructor
    // as providing just the char* pointer could result in garbage
    // at the end of the string (no guarantee of null terminator).
    return new string(reversed, 0, len);
}

以下是一些基准测试结果.

Array.Reverse随着字符串变大,您可以看到性能增益收缩然后消失.但是对于中小型琴弦来说,很难击败这种方法.


大字符串上的StackOverflow.

8> Mehdi Khadem..:

简单而好的答案是使用扩展方法:

static class ExtentionMethodCollection
{
    public static string Inverse(this string @base)
    {
        return new string(@base.Reverse().ToArray());
    }
}

这是输出:

string Answer = "12345".Inverse(); // = "54321"



9> Greg Beech..:

如果你想玩一个非常危险的游戏,那么这是迄今为止最快的方式(比Array.Reverse方法快四倍).这是使用指针的就地反向.

请注意,我真的不推荐这个用于任何用途(看看这里有一些原因,你不应该使用这个方法),但是看到它可以完成,并且字符串不是真正不可变的,这很有趣一旦你打开不安全的代码.

public static unsafe string Reverse(string text)
{
    if (string.IsNullOrEmpty(text))
    {
        return text;
    }

    fixed (char* pText = text)
    {
        char* pStart = pText;
        char* pEnd = pText + text.Length - 1;
        for (int i = text.Length / 2; i >= 0; i--)
        {
            char temp = *pStart;
            *pStart++ = *pEnd;
            *pEnd-- = temp;
        }

        return text;
    }
}



10> Mike Thompso..:

在这里查看维基百科条目.它们实现String.Reverse扩展方法.这允许您编写如下代码:

string s = "olleh";
s.Reverse();

他们还使用ToCharArray/Reverse组合,这个问题的其他答案表明.源代码如下所示:

public static string Reverse(this string input)
{
    char[] chars = input.ToCharArray();
    Array.Reverse(chars);
    return new String(chars);
}



11> Greg Beech..:

首先,您不需要调用ToCharArray字符串已经可以索引为char数组,因此这将为您节省分配.

下一个优化是使用a StringBuilder来防止不必要的分配(因为字符串是不可变的,连接它们每次都会生成字符串的副本).为了进一步优化这个,我们预先设置了StringBuilder它的长度,因此不需要扩展它的缓冲区.

public string Reverse(string text)
{
    if (string.IsNullOrEmpty(text))
    {
        return text;
    }

    StringBuilder builder = new StringBuilder(text.Length);
    for (int i = text.Length - 1; i >= 0; i--)
    {
        builder.Append(text[i]);
    }

    return builder.ToString();
}

编辑:效果数据

我使用Array.Reverse以下简单程序测试了这个函数和函数,其中Reverse1一个是函数,另一个函数Reverse2是:

static void Main(string[] args)
{
    var text = "abcdefghijklmnopqrstuvwxyz";

    // pre-jit
    text = Reverse1(text); 
    text = Reverse2(text);

    // test
    var timer1 = Stopwatch.StartNew();
    for (var i = 0; i < 10000000; i++)
    {
        text = Reverse1(text);
    }

    timer1.Stop();
    Console.WriteLine("First: {0}", timer1.ElapsedMilliseconds);

    var timer2 = Stopwatch.StartNew();
    for (var i = 0; i < 10000000; i++)
    {
        text = Reverse2(text);
    }

    timer2.Stop();
    Console.WriteLine("Second: {0}", timer2.ElapsedMilliseconds);

    Console.ReadLine();
}

事实证明,对于短弦乐队来说,这种Array.Reverse方法的速度大约是上面的两倍,而对于较长的琴弦,差异甚至更明显.因此,鉴于该Array.Reverse方法既简单又快捷,我建议您使用它而不是这个.我把这个留在这里只是为了表明这不是你应该这样做的方式(令我惊讶的是!)



12> Mike Two..:

尝试使用Array.Reverse

public string Reverse(string str)
{
    char[] array = str.ToCharArray();
    Array.Reverse(array);
    return new string(array);
}



13> Vlad Bezden..:
public static string Reverse(string input)
{
    return string.Concat(Enumerable.Reverse(input));
}

当然,您可以使用Reverse方法扩展字符串类

public static class StringExtensions
{
    public static string Reverse(this string input)
    {
        return string.Concat(Enumerable.Reverse(input));
    }
}



14> B H..:

不要打扰功能,只需这样做.注意:第二行将在某些VS版本的立即窗口中引发参数异常.

string s = "Blah";
s = new string(s.ToCharArray().Reverse().ToArray()); 



15> Slai..:

"最好的"可以取决于许多事情,但这里有一些从快到慢排序的简短替代品:

string s = "z?a?l?g?o?", pattern = @"(?s).(?<=(?:.(?=.*$(?<=((\P{M}\p{C}?\p{M}*)\1?))))*)";

string s1 = string.Concat(s.Reverse());                          // "???o?g?l?a?z"  

string s2 = Microsoft.VisualBasic.Strings.StrReverse(s);         // "o?g?l?a??z"  

string s3 = string.Concat(StringInfo.ParseCombiningCharacters(s).Reverse()
    .Select(i => StringInfo.GetNextTextElement(s, i)));          // "o?g?l?a?z?"  

string s4 = Regex.Replace(s, pattern, "$2").Remove(s.Length);    // "o?g?l?a?z?"  



16> aku..:

抱歉,很长的帖子,但这可能很有趣

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        public static string ReverseUsingArrayClass(string text)
        {
            char[] chars = text.ToCharArray();
            Array.Reverse(chars);
            return new string(chars);
        }

        public static string ReverseUsingCharacterBuffer(string text)
        {
            char[] charArray = new char[text.Length];
            int inputStrLength = text.Length - 1;
            for (int idx = 0; idx <= inputStrLength; idx++) 
            {
                charArray[idx] = text[inputStrLength - idx];                
            }
            return new string(charArray);
        }

        public static string ReverseUsingStringBuilder(string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                return text;
            }

            StringBuilder builder = new StringBuilder(text.Length);
            for (int i = text.Length - 1; i >= 0; i--)
            {
                builder.Append(text[i]);
            }

            return builder.ToString();
        }

        private static string ReverseUsingStack(string input)
        {
            Stack resultStack = new Stack();
            foreach (char c in input)
            {
                resultStack.Push(c);
            }

            StringBuilder sb = new StringBuilder();
            while (resultStack.Count > 0)
            {
                sb.Append(resultStack.Pop());
            }
            return sb.ToString();
        }

        public static string ReverseUsingXOR(string text)
        {
            char[] charArray = text.ToCharArray();
            int length = text.Length - 1;
            for (int i = 0; i < length; i++, length--)
            {
                charArray[i] ^= charArray[length];
                charArray[length] ^= charArray[i];
                charArray[i] ^= charArray[length];
            }

            return new string(charArray);
        }


        static void Main(string[] args)
        {
            string testString = string.Join(";", new string[] {
                new string('a', 100), 
                new string('b', 101), 
                new string('c', 102), 
                new string('d', 103),                                                                   
            });
            int cycleCount = 100000;

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < cycleCount; i++) 
            {
                ReverseUsingCharacterBuffer(testString);
            }
            stopwatch.Stop();
            Console.WriteLine("ReverseUsingCharacterBuffer: " + stopwatch.ElapsedMilliseconds + "ms");

            stopwatch.Reset();
            stopwatch.Start();
            for (int i = 0; i < cycleCount; i++) 
            {
                ReverseUsingArrayClass(testString);
            }
            stopwatch.Stop();
            Console.WriteLine("ReverseUsingArrayClass: " + stopwatch.ElapsedMilliseconds + "ms");

            stopwatch.Reset();
            stopwatch.Start();
            for (int i = 0; i < cycleCount; i++) 
            {
                ReverseUsingStringBuilder(testString);
            }
            stopwatch.Stop();
            Console.WriteLine("ReverseUsingStringBuilder: " + stopwatch.ElapsedMilliseconds + "ms");

            stopwatch.Reset();
            stopwatch.Start();
            for (int i = 0; i < cycleCount; i++) 
            {
                ReverseUsingStack(testString);
            }
            stopwatch.Stop();
            Console.WriteLine("ReverseUsingStack: " + stopwatch.ElapsedMilliseconds + "ms");

            stopwatch.Reset();
            stopwatch.Start();
            for (int i = 0; i < cycleCount; i++) 
            {
                ReverseUsingXOR(testString);
            }
            stopwatch.Stop();
            Console.WriteLine("ReverseUsingXOR: " + stopwatch.ElapsedMilliseconds + "ms");            
        }
    }
}

结果:

ReverseUsingCharacterBuffer:346ms

ReverseUsingArrayClass:87毫秒

ReverseUsingStringBuilder:824ms

ReverseUsingStack:2086ms

ReverseUsingXOR:319ms

推荐阅读
有风吹过best
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有