C# 反转字符串的最佳方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/228038/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to reverse a string
提问by Guy
I've just had to write a string reverse function in C# 2.0 (i.e. LINQ not available) and came up with this:
我只需要在 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;
}
Personally I'm not crazy about the function and am convinced that there's a better way to do it. Is there?
就我个人而言,我对这个功能并不着迷,并且相信有更好的方法来做到这一点。在那儿?
采纳答案by PeteT
public static string Reverse( string s )
{
char[] charArray = s.ToCharArray();
Array.Reverse( charArray );
return new string( charArray );
}
回答by Mike Thompson
Have a look at the wikipedia entry here. They implement the String.Reverse extension method. This allows you to write code like this:
在这里查看维基百科条目。它们实现了 String.Reverse 扩展方法。这允许您编写如下代码:
string s = "olleh";
s.Reverse();
They also use the ToCharArray/Reverse combination that other answers to this question suggest. The source code looks like this:
他们还使用此问题的其他答案所建议的 ToCharArray/Reverse 组合。源代码如下所示:
public static string Reverse(this string input)
{
char[] chars = input.ToCharArray();
Array.Reverse(chars);
return new String(chars);
}
回答by Greg Beech
Firstly you don't need to call ToCharArray
as a string can already be indexed as a char array, so this will save you an allocation.
首先,您不需要调用,ToCharArray
因为字符串已经可以索引为字符数组,因此这将为您节省分配。
The next optimisation is to use a StringBuilder
to prevent unnecessary allocations (as strings are immutable, concatenating them makes a copy of the string each time). To further optimise this we pre-set the length of the StringBuilder
so it won't need to expand its buffer.
下一个优化是使用 aStringBuilder
来防止不必要的分配(因为字符串是不可变的,每次连接它们都会生成一个字符串的副本)。为了进一步优化这一点,我们预先设置了 的长度,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();
}
Edit: Performance Data
编辑:性能数据
I tested this function and the function using Array.Reverse
with the following simple program, where Reverse1
is one function and Reverse2
is the other:
我使用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();
}
It turns out that for short strings the Array.Reverse
method is around twice as quick as the one above, and for longer strings the difference is even more pronounced. So given that the Array.Reverse
method is both simpler and faster I'd recommend you use that rather than this one. I leave this one up here just to show that it isn't the way you should do it (much to my surprise!)
事实证明,对于短字符串,该Array.Reverse
方法的速度大约是上述方法的两倍,而对于较长的字符串,差异更加明显。因此,鉴于该Array.Reverse
方法既简单又快捷,我建议您使用该方法而不是此方法。我把这个留在这里只是为了表明这不是你应该做的(令我惊讶的是!)
回答by Sam Saffron
This is turning out to be a surprisingly tricky question.
事实证明,这是一个令人惊讶的棘手问题。
I would recommend using Array.Reverse for most cases as it is coded natively and it is very simple to maintain and understand.
我建议在大多数情况下使用 Array.Reverse,因为它是本机编码的,并且非常易于维护和理解。
It seems to outperform StringBuilder in all the cases I tested.
在我测试的所有情况下,它似乎都优于 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);
}
There is a second approach that can be faster for certain string lengths which uses Xor.
对于使用 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);
}
NoteIf you want to support the full Unicode UTF16 charset read this. And use the implementation there instead. It can be further optimized by using one of the above algorithms and running through the string to clean it up after the chars are reversed.
注意如果您想支持完整的 Unicode UTF16 字符集,请阅读此. 并在那里使用实现。可以通过使用上述算法之一并在字符反转后运行字符串以对其进行清理来进一步优化。
Here is a performance comparison between the StringBuilder, Array.Reverse and Xor method.
下面是 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();
}
}
}
Here are the results:
结果如下:
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.
It seems that Xor can be faster for short strings.
对于短字符串,Xor 似乎可以更快。
回答by Ash
"Better way" depends on what is more important to you in your situation, performance, elegance, maintainability etc.
“更好的方式”取决于在您的情况、性能、优雅、可维护性等方面对您来说更重要的是什么。
Anyway, here's an approach using Array.Reverse:
无论如何,这是一种使用 Array.Reverse 的方法:
string inputString="The quick brown fox jumps over the lazy dog.";
char[] charArray = inputString.ToCharArray();
Array.Reverse(charArray);
string reversed = new string(charArray);
回答by Mike Two
Try using Array.Reverse
尝试使用 Array.Reverse
public string Reverse(string str)
{
char[] array = str.ToCharArray();
Array.Reverse(array);
return new string(array);
}
回答by JPrescottSanders
Had to submit a recursive example:
必须提交一个递归示例:
private static string Reverse(string str)
{
if (str.IsNullOrEmpty(str) || str.Length == 1)
return str;
else
return str[str.Length - 1] + Reverse(str.Substring(0, str.Length - 1));
}
回答by aku
Sorry for long post, but this might be interesting
抱歉长篇幅,但这可能很有趣
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<char> resultStack = new Stack<char>();
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");
}
}
}
Results:
结果:
- ReverseUsingCharacterBuffer: 346ms
- ReverseUsingArrayClass: 87ms
- ReverseUsingStringBuilder: 824ms
- ReverseUsingStack: 2086ms
- ReverseUsingXOR: 319ms
- 反向使用字符缓冲区:346 毫秒
- 反向使用数组类:87ms
- 反向使用StringBuilder:824ms
- 反向使用堆栈:2086 毫秒
- 反向使用异或:319ms
回答by Greg Beech
If you want to play a really dangerous game, then this is by far the fastest way there is (around four times faster than the Array.Reverse
method). It's an in-place reverse using pointers.
如果您想玩真正危险的游戏,那么这是迄今为止最快的方法(大约比该Array.Reverse
方法快四倍)。这是使用指针的就地反转。
Note that I really do not recommend this for any use, ever (have a look here for some reasons why you should not use this method), but it's just interesting to see that it can be done, and that strings aren't really immutable once you turn on unsafe code.
请注意,我真的不建议将其用于任何用途(出于某些原因,您不应该使用此方法,请查看此处),但有趣的是它可以完成,并且字符串并不是真正不可变的一旦你打开不安全代码。
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;
}
}
回答by Bradley Grainger
If the string contains Unicode data (strictly speaking, non-BMP characters) the other methods that have been posted will corrupt it, because you cannot swap the order of high and low surrogate code units when reversing the string. (More information about this can be found on my blog.)
如果字符串包含 Unicode 数据(严格来说,非 BMP 字符),其他已发布的方法将破坏它,因为在反转字符串时您无法交换高低代理代码单元的顺序。(有关这方面的更多信息可以在我的博客上找到。)
The following code sample will correctly reverse a string that contains non-BMP characters, e.g., "\U00010380\U00010381" (Ugaritic Letter Alpa, Ugaritic Letter Beta).
以下代码示例将正确反转包含非 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);
}