방금 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;
}
개인적으로 나는 그 기능에 열중하지 않으며 더 좋은 방법이 있다고 확신합니다. 있습니까?
답변
public static string Reverse( string s )
{
char[] charArray = s.ToCharArray();
Array.Reverse( charArray );
return new string( charArray );
}
답변
여기에서 문자열을 "Les Mise\u0301rables"
로 올바르게 뒤집는 해결책이 "selbare\u0301siM seL"
있습니다. 이는 코드 단위 ( 등) 또는 심지어 코드 포인트 (대리 쌍에 특별한주의를 기울임)를 기반으로 한 대부분의 구현 결과와 마찬가지로 (강조의 위치에 유의 selbarésiM seL
하지 않음) 처럼 렌더링되어야 selbaŕesiM seL
합니다 Array.Reverse
.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
public static class Test
{
private static IEnumerable<string> 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 )
그것은 그 이후로 존재했던 grapheme cluster iteration을 위해 .NET API를 사용 하지만,보기에서 약간 “숨겨진”것 같습니다.
답변
이것은 놀랍도록 까다로운 질문으로 판명되었습니다.
Array.Reverse는 기본적으로 코딩되어 있으며 유지 관리 및 이해가 매우 간단하므로 대부분의 경우 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);
}
참고 전체 유니 코드 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가 더 빠를 수 있습니다.
답변
하나의 라이너를 따르는 것보다 LINQ (.NET Framework 3.5 이상)를 사용할 수 있다면 짧은 코드가 제공됩니다. 다음에 using System.Linq;
액세스 할 수 있도록 추가 하는 것을 잊지 마십시오 Enumerable.Reverse
.
public string ReverseString(string srtVarable)
{
return new string(srtVarable.Reverse().ToArray());
}
노트:
- Martin Niederl 에 따르면 가장 빠른 버전은 아닙니다 . 여기에서 가장 빠른 선택보다 5.7 배 느립니다.
- 이 코드는 다른 많은 옵션과 마찬가지로 모든 종류의 다중 문자 조합을 완전히 무시하므로 이러한 문자를 포함 하지 않는 숙제 및 문자열로 사용을 제한하십시오 . 이러한 조합을 올바르게 처리하는 구현에 대해서는이 질문의 다른 답변 을 참조하십시오 .
답변
문자열에 유니 코드 데이터 (엄격하게 말하면 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);
}
답변
“반복하지 마십시오”라는 관심을 가지고 다음 해결책을 제시합니다.
public string Reverse(string text)
{
return Microsoft.VisualBasic.Strings.StrReverse(text);
}
VB.NET에서 기본적으로 사용 가능한이 구현은 유니 코드 문자를 올바르게 처리한다는 것을 이해하고 있습니다.
답변
Greg Beech unsafe
는 실제로 가능한 한 빠른 옵션을 게시했습니다 (현재 위치 반전). 그러나 그의 답변에서 지적 했듯이 그것은 완전히 비참한 생각 입니다.
즉 Array.Reverse
, 가장 빠른 방법 인 합의가 너무 놀랐습니다 . 작은 문자열에 대한 방법 보다unsafe
문자열의 역 복사본을 반환 하는 방법 이 있습니다 (현재 위치 반전 shenanigans 없음) .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
문자열이 커짐 에 따라 성능 향상이 줄어들었다가 메서드 에 대해 사라지는 것을 볼 수 있습니다 . 그러나 중소형 스트링의 경우이 방법을 능가하기가 어렵습니다.
