我刚刚在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;
}

就我个人而言,我并不喜欢这个功能,我相信有更好的方法来实现它。是吗?


当前回答

首先,你必须理解的是str+=将调整字符串内存大小,为1个额外的字符腾出空间。这很好,但是如果你有一本1000页的书,你想要反转,这将需要很长时间来执行。

有些人建议的解决方案是使用StringBuilder。字符串构建器在执行+=时所做的是分配更大的内存块来保存新字符,这样它就不需要在每次添加字符时进行重新分配。

如果你真的想要一个快速和最小的解决方案,我建议如下:

            char[] chars = new char[str.Length];
            for (int i = str.Length - 1, j = 0; i >= 0; --i, ++j)
            {
                chars[j] = str[i];
            }
            str = new String(chars);

在这个解决方案中,在初始化char[]时有一个初始内存分配,在string构造函数从char数组构建字符串时有一个初始内存分配。

在我的系统上,我为您运行了一个测试,反转了一个2750,000个字符的字符串。以下是10次执行的结果:

StringBuilder: 190K - 200K tick

字符数组:130K - 160K

我还运行了一个正常String +=的测试,但我在10分钟后放弃了它,没有输出。

但是,我也注意到,对于较小的字符串,StringBuilder更快,因此您必须根据输入来决定实现。

干杯

其他回答

    string original = "Stack Overflow";
    string reversed = new string(original.Reverse().ToArray());

如果有人问关于字符串反向的问题,其目的可能是想知道你是否知道任何位操作,比如异或。c#中有数组。反向函数,但是,您可以使用简单的异或操作在几行代码(最少)

    public static string MyReverse(string s)
    {
        char[] charArray = s.ToCharArray();
        int bgn = -1;
        int end = s.Length;
        while(++bgn < --end)
        {
            charArray[bgn] ^= charArray[end];
            charArray[end] ^= charArray[bgn];
            charArray[bgn] ^= charArray[end];
        }
        return new string(charArray);
    }

在使用StringInfo.GetTextElementEnumerator()的地方有几个正确答案。向你致敬!

现在,让我们找出最有效的方法来使用这个方法。首先,大多数答案涉及调用Reverse()和ToArray(),这在热路径上是一个大禁忌。为了获得最佳性能,我们希望避免分配垃圾。例如,临时字符串,分配器,数组等。

优化的管柱反转

降低气相色谱压力。也就是说,没有LINQ枚举器,没有数组。 使用跨 使用String.Create ()

using System.Globalization;

public static class StringExtensions
{
    public static string AsReversed(this string s)
    {
        return string.Create(s.Length, s, (chars, state) =>
        {
            int i = 0;
            var enumerator = StringInfo.GetTextElementEnumerator(s);
            while (enumerator.MoveNext())
            {
                var element = enumerator.GetTextElement();
                i += element.Length;
                element.CopyTo(chars[^i..]);
            }
        });
    }
}

请注意,GetTextElementEnumerator() API在. net Core 3.1和更早的版本中包含一个错误。确保运行。net 5或更高版本!最后,请务必查看正在讨论API改进的问题#19423。

private static string Reverse(string str)
        {
            string revStr = string.Empty;
            for (int i = str.Length - 1; i >= 0; i--)
            {
                revStr += str[i].ToString();
            }
            return revStr;
        }

比上述方法快

private static string ReverseEx(string str)
        {
            char[] chrArray = str.ToCharArray();
            int len = chrArray.Length - 1;
            char rev = 'n';
            for (int i = 0; i <= len/2; i++)
            {
                rev = chrArray[i];
                chrArray[i] = chrArray[len - i];
                chrArray[len - i] = rev;
            }
            return new string(chrArray);
        }

Greg Beech发布了一个不安全的选项,它确实很快(这是一个原地逆转);但是,正如他在回答中指出的那样,这完全是一个灾难性的想法。

也就是说,我很惊讶有这么多的共识,Array。逆向是最快的方法。仍然有一种不安全的方法,它返回字符串的反向副本(没有原地反转的恶作剧),比Array快得多。小字符串的反向方法:

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,性能增益会缩小,然后消失。当字符串变大时,反向方法。然而,对于小型到中型的字符串,很难击败这种方法。