web-dev-qa-db-de.com

Beste Weg, um eine Zeichenfolge umzukehren

Ich musste nur eine String-Reverse-Funktion in C # 2.0 schreiben (d. H. LINQ ist nicht verfügbar) und habe Folgendes gefunden:

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;
}

Persönlich bin ich nicht verrückt nach der Funktion und bin überzeugt, dass es einen besseren Weg gibt, dies zu tun. Gibt es?

403
Guy
public static string Reverse( string s )
{
    char[] charArray = s.ToCharArray();
    Array.Reverse( charArray );
    return new string( charArray );
}
533
PeteT

Hier eine Lösung, die den String "Les Mise\u0301rables" korrekt als "selbare\u0301siM seL" umkehrt. Dies sollte genau wie selbarésiM seL und nicht wie selbaŕesiM seL (beachten Sie die Position des Akzents) gerendert werden, ebenso wie das Ergebnis der meisten Implementierungen, die auf Codeeinheiten (Array.Reverse usw.) oder sogar Codepunkten basieren (Umkehrung mit besonderer Sorgfalt für Ersatzpaare).

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);
    }
}

(Und Live Running Beispiel hier: https://ideone.com/DqAeMJ )

Es wird einfach die .NET API für Graphem-Cluster-Iteration verwendet, die es seit jeher gibt, aber ein bisschen "versteckt" zu sein scheint.

167

Dies ist eine überraschend knifflige Frage.

Ich würde empfehlen, Array.Reverse für die meisten Fälle zu verwenden, da es nativ codiert ist und sehr einfach zu warten und zu verstehen ist.

Es scheint StringBuilder in allen von mir getesteten Fällen zu übertreffen.

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);
}

Es gibt einen zweiten Ansatz, der für bestimmte Zeichenfolgenlängen schneller sein kann: verwendet 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);
    }

Hinweis Wenn Sie den vollständigen Unicode UTF16-Zeichensatz unterstützen möchten lesen Sie dies . Und verwenden Sie stattdessen die Implementierung dort. Es kann weiter optimiert werden, indem einer der obigen Algorithmen verwendet und die Zeichenfolge nach dem Umkehren der Zeichen durchlaufen wird, um sie zu bereinigen.

Hier ist ein Leistungsvergleich zwischen der StringBuilder-, Array.Reverse- und der Xor-Methode.

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();
        }
    }
}

Hier sind die Ergebnisse:

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.

Es scheint, dass Xor für kurze Saiten schneller sein kann.

125
Sam Saffron

Wenn die Zeichenfolge Unicode-Daten enthält (streng genommen Nicht-BMP-Zeichen), werden sie durch die anderen Methoden beschädigt, da Sie beim Umkehren der Zeichenfolge die Reihenfolge der hohen und niedrigen Ersatzcodeeinheiten nicht vertauschen können. (Weitere Informationen dazu finden Sie unter mein Blog .)

Das folgende Codebeispiel kehrt eine Zeichenfolge, die Nicht-BMP-Zeichen enthält, korrekt um, z. B. "\ 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);
}
49

Von oben 3.5 Framework

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

Ok, im Interesse von "Wiederhole dich nicht" biete ich die folgende Lösung an:

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

Ich verstehe, dass diese Implementierung, die standardmäßig in VB.NET verfügbar ist, Unicode-Zeichen ordnungsgemäß verarbeitet.

23
richardtallent

Greg Beech hat eine unsafe Option veröffentlicht, die in der Tat so schnell wie möglich ist (es handelt sich um eine In-Place-Umkehrung). aber, wie er in seiner Antwort anzeigte, ist es eine völlig katastrophale Idee.

Das heißt, ich bin überrascht, dass es so viel Konsens gibt, dass Array.Reverse die schnellste Methode ist. Es gibt immer noch einen unsafe -Ansatz, der eine umgekehrte Kopie einer Zeichenfolge zurückgibt (keine In-Place-Umkehrung) , und zwar erheblich schneller als die Array.Reverse -Methode für kleine Saiten:

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);
}

Hier sind einige Benchmark-Ergebnisse .

Sie können sehen, dass der Leistungszuwachs abnimmt und dann bei Verwendung der Array.Reverse -Methode verschwindet, wenn die Zeichenfolgen größer werden. Für kleine bis mittelgroße Saiten ist es jedoch schwierig, diese Methode zu übertreffen.

17
Dan Tao

Die einfache und nette Antwort verwendet die Extension-Methode:

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

und hier ist die Ausgabe:

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

Wenn Sie ein wirklich gefährliches Spiel spielen möchten, ist dies bei weitem der schnellste Weg (ungefähr viermal schneller als die Array.Reverse -Methode). Es ist ein In-Place-Reverse mit Zeigern.

Beachten Sie, dass ich dies niemals wirklich empfehlen werde ( schauen Sie hier aus einigen Gründen nach, warum Sie diese Methode nicht verwenden sollten ), aber es ist nur interessant zu sehen, dass dies möglich ist, und Diese Zeichenfolgen sind nicht wirklich unveränderlich, sobald Sie unsicheren Code aktivieren.

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;
    }
}
13
Greg Beech

Schauen Sie sich den Wikipedia-Eintrag an hier . Sie implementieren die String.Reverse-Erweiterungsmethode. Auf diese Weise können Sie Code wie folgt schreiben:

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

Sie verwenden auch die ToCharArray/Reverse-Kombination, die andere Antworten auf diese Frage vorschlagen. Der Quellcode sieht folgendermaßen aus:

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

Erstens müssen Sie ToCharArray nicht aufrufen, da ein String bereits als Zeichen-Array indiziert werden kann, sodass Sie eine Zuordnung sparen.

Die nächste Optimierung besteht darin, ein StringBuilder zu verwenden, um unnötige Zuweisungen zu verhindern (da Zeichenfolgen unveränderlich sind, wird durch ihre Verkettung jedes Mal eine Kopie der Zeichenfolge erstellt). Um dies weiter zu optimieren, haben wir die Länge von StringBuilder voreingestellt, damit der Puffer nicht erweitert werden muss.

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();
}

Bearbeiten: Leistungsdaten

Ich habe diese Funktion und die Funktion mit Array.Reverse mit dem folgenden einfachen Programm getestet, wobei Reverse1 eine Funktion und Reverse2 die andere ist:

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();
}

Es stellt sich heraus, dass die Array.Reverse -Methode für kurze Zeichenfolgen etwa doppelt so schnell ist wie die oben beschriebene, und bei längeren Zeichenfolgen ist der Unterschied sogar noch ausgeprägter. Angesichts der Tatsache, dass die Array.Reverse -Methode sowohl einfacher als auch schneller ist, würde ich empfehlen, dass Sie diese Methode anstelle dieser verwenden. Ich lasse dieses hier oben, nur um zu zeigen, dass es nicht so ist, wie Sie es tun sollten (sehr zu meiner Überraschung!)

11
Greg Beech
public static string Reverse(string input)
{
    return string.Concat(Enumerable.Reverse(input));
}

Natürlich können Sie die String-Klasse mit der Reverse-Methode erweitern

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

Versuchen Sie es mit Array.Reverse


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

Mach dir keine Sorgen mit einer Funktion, mach es einfach an Ort und Stelle. Hinweis: Die zweite Zeile löst bei einigen VS-Versionen eine Argumentausnahme im Direktfenster aus.

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

Entschuldigung für den langen Beitrag, aber das könnte interessant sein

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");            
        }
    }
}

Ergebnisse:

  • ReverseUsingCharacterBuffer: 346ms
  • ReverseUsingArrayClass: 87ms
  • ReverseUsingStringBuilder: 824ms
  • ReverseUsingStack: 2086ms
  • ReverseUsingXOR: 319ms
5
aku

"Best" kann von vielen Dingen abhängen, aber hier sind noch ein paar kurze Alternativen, die von schnell zu langsam geordnet sind:

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

string s1 = string.Concat(s.Reverse());                          // "☐????☐̓ö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̽"  ????
5
Slai
public string Reverse(string input)
{
    char[] output = new char[input.Length];

    int forwards = 0;
    int backwards = input.Length - 1;

    do
    {
        output[forwards] = input[backwards];
        output[backwards] = input[forwards];
    }while(++forwards <= --backwards);

    return new String(output);
}

public string DotNetReverse(string input)
{
    char[] toReverse = input.ToCharArray();
    Array.Reverse(toReverse);
    return new String(toReverse);
}

public string NaiveReverse(string input)
{
    char[] outputArray = new char[input.Length];
    for (int i = 0; i < input.Length; i++)
    {
        outputArray[i] = input[input.Length - 1 - i];
    }

    return new String(outputArray);
}    

public string RecursiveReverse(string input)
{
    return RecursiveReverseHelper(input, 0, input.Length - 1);
}

public string RecursiveReverseHelper(string input, int startIndex , int endIndex)
{
    if (startIndex == endIndex)
    {
        return "" + input[startIndex];
    }

    if (endIndex - startIndex == 1)
    {
        return "" + input[endIndex] + input[startIndex];
    }

    return input[endIndex] + RecursiveReverseHelper(input, startIndex + 1, endIndex - 1) + input[startIndex];
}


void Main()
{
    int[] sizes = new int[] { 10, 100, 1000, 10000 };
    for(int sizeIndex = 0; sizeIndex < sizes.Length; sizeIndex++)
    {
        string holaMundo  = "";
        for(int i = 0; i < sizes[sizeIndex]; i+= 5)
        {   
            holaMundo += "ABCDE";
        }

        string.Format("\n**** For size: {0} ****\n", sizes[sizeIndex]).Dump();

        string odnuMaloh = DotNetReverse(holaMundo);

        var stopWatch = Stopwatch.StartNew();
        string result = NaiveReverse(holaMundo);
        ("Naive Ticks: " + stopWatch.ElapsedTicks).Dump();

        stopWatch.Restart();
        result = Reverse(holaMundo);
        ("Efficient linear Ticks: " + stopWatch.ElapsedTicks).Dump();

        stopWatch.Restart();
        result = RecursiveReverse(holaMundo);
        ("Recursive Ticks: " + stopWatch.ElapsedTicks).Dump();

        stopWatch.Restart();
        result = DotNetReverse(holaMundo);
        ("DotNet Reverse Ticks: " + stopWatch.ElapsedTicks).Dump();
    }
}

Ausgabe

Für Größe: 1

Naive Ticks: 1
Efficient linear Ticks: 0
Recursive Ticks: 2
DotNet Reverse Ticks: 1

Für Größe: 1

Naive Ticks: 2
Efficient linear Ticks: 1
Recursive Ticks: 12
DotNet Reverse Ticks: 1

Für Größe: 10

Naive Ticks: 5
Efficient linear Ticks: 2
Recursive Ticks: 358
DotNet Reverse Ticks: 9

Für Größe: 100

Naive Ticks: 32
Efficient linear Ticks: 28
Recursive Ticks: 84808
DotNet Reverse Ticks: 33

Stack-basierte Lösung.

    public static string Reverse(string text)
    {
        var stack = new Stack<char>(text);
        var array = new char[stack.Count];

        int i = 0;
        while (stack.Count != 0)
        {
            array[i++] = stack.Pop();
        }

        return new string(array);
    }

Oder

    public static string Reverse(string text)
    {
        var stack = new Stack<char>(text);
        return string.Join("", stack);
    }
4
Raz Megrelidze

Einfachster Weg:

string reversed = new string(text.Reverse().ToArray());
4
Shady Sirhan

Musste ein rekursives Beispiel einreichen:

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));
}
4

Ich habe einen C # -Port von Microsoft.VisualBasic.Strings erstellt. Ich bin nicht sicher, warum sie solche nützlichen Funktionen (von VB) außerhalb des System.String in Framework behalten, aber immer noch unter Microsoft.VisualBasic. Dasselbe Szenario für Finanzfunktionen (z. B. Microsoft.VisualBasic.Financial.Pmt()).

public static string StrReverse(this string expression)
{
    if ((expression == null))
        return "";

    int srcIndex;

    var length = expression.Length;
    if (length == 0)
        return "";

    //CONSIDER: Get System.String to add a surrogate aware Reverse method

    //Detect if there are any graphemes that need special handling
    for (srcIndex = 0; srcIndex <= length - 1; srcIndex++)
    {
        var ch = expression[srcIndex];
        var uc = char.GetUnicodeCategory(ch);
        if (uc == UnicodeCategory.Surrogate || uc == UnicodeCategory.NonSpacingMark || uc == UnicodeCategory.SpacingCombiningMark || uc == UnicodeCategory.EnclosingMark)
        {
            //Need to use special handling
            return InternalStrReverse(expression, srcIndex, length);
        }
    }

    var chars = expression.ToCharArray();
    Array.Reverse(chars);
    return new string(chars);
}

///<remarks>This routine handles reversing Strings containing graphemes
/// GRAPHEME: a text element that is displayed as a single character</remarks>
private static string InternalStrReverse(string expression, int srcIndex, int length)
{
    //This code can only be hit one time
    var sb = new StringBuilder(length) { Length = length };

    var textEnum = StringInfo.GetTextElementEnumerator(expression, srcIndex);

    //Init enumerator position
    if (!textEnum.MoveNext())
    {
        return "";
    }

    var lastSrcIndex = 0;
    var destIndex = length - 1;

    //Copy up the first surrogate found
    while (lastSrcIndex < srcIndex)
    {
        sb[destIndex] = expression[lastSrcIndex];
        destIndex -= 1;
        lastSrcIndex += 1;
    }

    //Now iterate through the text elements and copy them to the reversed string
    var nextSrcIndex = textEnum.ElementIndex;

    while (destIndex >= 0)
    {
        srcIndex = nextSrcIndex;

        //Move to next element
        nextSrcIndex = (textEnum.MoveNext()) ? textEnum.ElementIndex : length;
        lastSrcIndex = nextSrcIndex - 1;

        while (lastSrcIndex >= srcIndex)
        {
            sb[destIndex] = expression[lastSrcIndex];
            destIndex -= 1;
            lastSrcIndex -= 1;
        }
    }

    return sb.ToString();
}
3
natenho

Ab .NET Core 2.1 gibt es eine neue Möglichkeit, einen String mit der string.Create -Methode umzukehren.

Beachten Sie, dass diese Lösung Unicode-Zeichen usw. nicht korrekt verarbeitet, da "Les Mise\u0301rables" in "selbarésiM seL" konvertiert würde. Das die anderen Antworten für eine bessere Lösung.

public static string Reverse(string input)
{
    return string.Create<string>(input.Length, input, (chars, state) =>
    {
        state.AsSpan().CopyTo(chars);
        chars.Reverse();
    });
}

Dies kopiert im Wesentlichen die Zeichen von input in eine neue Zeichenfolge und kehrt die neue Zeichenfolge um.

Warum ist string.Create nützlich?

Wenn wir eine Zeichenfolge aus einem vorhandenen Array erstellen, wird ein neues internes Array zugewiesen und die Werte werden kopiert. Andernfalls ist es möglich, einen String nach seiner Erstellung (in einer sicheren Umgebung) zu mutieren. Das heißt, im folgenden Snippet müssen wir ein Array der Länge 10 zweimal zuweisen, eines als Puffer und eines als internes Array des Strings.

var chars = new char[10];
// set array values
var str = new string(chars);

string.Create ermöglicht es uns im Wesentlichen, das interne Array während der Erstellungszeit des Strings zu manipulieren. Dies bedeutet, dass wir keinen Puffer mehr benötigen und daher die Zuweisung dieses einen Zeichen-Arrays vermeiden können.

Steve Gordon hat ausführlicher darüber geschrieben hier . Es gibt auch einen Artikel über MSDN .

Wie benutzt man string.Create?

public static string Create<TState>(int length, TState state, SpanAction<char, TState> action);

Die Methode akzeptiert drei Parameter:

  1. Die Länge der zu erstellenden Zeichenfolge.
  2. die Daten, die Sie zum dynamischen Erstellen der neuen Zeichenfolge verwenden möchten,
  3. und einen Delegaten, der die endgültige Zeichenfolge aus den Daten erstellt, wobei der erste Parameter auf das interne Array char der neuen Zeichenfolge verweist und der zweite die an string.Create übergebenen Daten (Status) darstellt.

Innerhalb des Delegaten können wir festlegen, wie der neue String aus den Daten erstellt wird. In unserem Fall kopieren wir einfach die Zeichen der Eingabezeichenfolge in das von der neuen Zeichenfolge verwendete Span. Dann kehren wir Span um und daher wird die gesamte Zeichenfolge umgekehrt.

Benchmarks

Um meine vorgeschlagene Methode zum Umkehren eines Strings mit der akzeptierten Antwort zu vergleichen, habe ich zwei Benchmarks mit BenchmarkDotNet geschrieben.

public class StringExtensions
{
    public static string ReverseWithArray(string input)
    {
        var charArray = input.ToCharArray();
        Array.Reverse(charArray);
        return new string(charArray);
    }

    public static string ReverseWithStringCreate(string input)
    {
        return string.Create(input.Length, input, (chars, state) =>
        {
            state.AsSpan().CopyTo(chars);
            chars.Reverse();
        });
    }
}

[MemoryDiagnoser]
public class StringReverseBenchmarks
{
    private string input;

    [Params(10, 100, 1000)]
    public int InputLength { get; set; }


    [GlobalSetup]
    public void SetInput()
    {
        // Creates a random string of the given length
        this.input = RandomStringGenerator.GetString(InputLength);
    }

    [Benchmark(Baseline = true)]
    public string WithReverseArray() => StringExtensions.ReverseWithArray(input);

    [Benchmark]
    public string WithStringCreate() => StringExtensions.ReverseWithStringCreate(input);
}

Hier sind die Ergebnisse auf meinem Computer:

| Method           | InputLength |         Mean |      Error |    StdDev |  Gen 0 | Allocated |
| ---------------- | ----------- | -----------: | ---------: | --------: | -----: | --------: |
| WithReverseArray | 10          |    45.464 ns |  0.4836 ns | 0.4524 ns | 0.0610 |      96 B |
| WithStringCreate | 10          |    39.749 ns |  0.3206 ns | 0.2842 ns | 0.0305 |      48 B |
|                  |             |              |            |           |        |           |
| WithReverseArray | 100         |   175.162 ns |  2.8766 ns | 2.2458 ns | 0.2897 |     456 B |
| WithStringCreate | 100         |   125.284 ns |  2.4657 ns | 2.0590 ns | 0.1473 |     232 B |
|                  |             |              |            |           |        |           |
| WithReverseArray | 1000        | 1,523.544 ns |  9.8808 ns | 8.7591 ns | 2.5768 |    4056 B |
| WithStringCreate | 1000        | 1,078.957 ns | 10.2948 ns | 9.6298 ns | 1.2894 |    2032 B |

Wie Sie sehen, weisen wir mit ReverseWithStringCreate nur die Hälfte des von der ReverseWithArray -Methode verwendeten Speichers zu.

3
Flogex

Wie wäre es mit:

    private string Reverse(string stringToReverse)
    {
        char[] rev = stringToReverse.Reverse().ToArray();
        return new string(rev); 
    }
3
Zamir

Entschuldigung für das Posten in diesem alten Thread. Ich übe Code für ein Interview.

Das war es, was ich mir für C # ausgedacht habe. Meine erste Version vor dem Refactoring war schrecklich.

static String Reverse2(string str)
{
    int strLen = str.Length, elem = strLen - 1;
    char[] charA = new char[strLen];

    for (int i = 0; i < strLen; i++)
    {
        charA[elem] = str[i];
        elem--;
    }

    return new String(charA);
}

Im Gegensatz zur unten stehenden Methode Array.Reverse wird sie mit maximal 12 Zeichen in der Zeichenfolge schneller angezeigt. Nach 13 Zeichen beginnt der Array.Reverse schneller zu werden, und schließlich dominiert er ziemlich stark die Geschwindigkeit. Ich wollte nur darauf hinweisen, wo sich die Geschwindigkeit zu ändern beginnt.

static String Reverse(string str)
{     
    char[] charA = str.ToCharArray();

    Array.Reverse(charA);

    return new String(charA);
}

Mit 100 Zeichen in der Zeichenfolge ist sie schneller als meine Version x 4. Wenn ich jedoch wüsste, dass die Zeichenfolgen immer kürzer als 13 Zeichen sind, würde ich die von mir erstellte verwenden.

Der Test wurde mit Stopwatch und 5000000 Iterationen durchgeführt. Ich bin mir auch nicht sicher, ob meine Version mit Surrogaten oder kombinierten Zeichensituationen mit Unicode Kodierung umgeht.

3
Jason Ausborn

Wenn Sie eine Zeichenfolge haben, die nur ASCII Zeichen enthält, können Sie diese Methode verwenden.

    public static string ASCIIReverse(string s)
    {
        byte[] reversed = new byte[s.Length];

        int k = 0;
        for (int i = s.Length - 1; i >= 0; i--)
        {
            reversed[k++] = (byte)s[i];
        }

        return Encoding.ASCII.GetString(reversed);
    }
2
Raz Megrelidze

Wenn es jemals in einem Interview auftauchte und Ihnen gesagt wurde, dass Sie Array.Reverse nicht verwenden können, denke ich, dass dies eines der schnellsten sein könnte. Es werden keine neuen Zeichenfolgen erstellt und nur über die Hälfte des Arrays iteriert (d. H. O(n/2) Iterationen).

    public static string ReverseString(string stringToReverse)
    {
        char[] charArray = stringToReverse.ToCharArray();
        int len = charArray.Length-1;
        int mid = len / 2;

        for (int i = 0; i < mid; i++)
        {
            char tmp = charArray[i];
            charArray[i] = charArray[len - i];
            charArray[len - i] = tmp;
        }
        return new string(charArray);
    }
2
mike01010

"Besserer Weg" hängt davon ab, was für Sie in Ihrer Situation, Leistung, Eleganz, Wartbarkeit usw. wichtiger ist.

Wie auch immer, hier ist ein Ansatz mit 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);
2
Ash
public static string reverse(string s) 
{
    string r = "";
    for (int i = s.Length; i > 0; i--) r += s[i - 1];
    return r;
}
2
ddagsan

Wie wäre es mit Substring

static string ReverseString(string text)
{
    string sub = "";
    int indexCount = text.Length - 1;
    for (int i = indexCount; i > -1; i--)
    {
        sub = sub + text.Substring(i, 1);
    }
    return sub;
}
1
joegreentea

Da mir einige Antworten gefallen - eine für die Verwendung von string.Create und daher für hohe Leistung und niedrige Zuordnung und eine andere für die Richtigkeit - für die Verwendung der Klasse StringInfo, habe ich beschlossen, dass ein kombinierter Ansatz erforderlich ist. Dies ist die ultimative String-Umkehrmethode :)

private static string ReverseString(string str)
    {
        return string.Create(str.Length, str, (chars, state) =>
        {
            var enumerator = StringInfo.GetTextElementEnumerator(state);
            var position = state.Length;
            while (enumerator.MoveNext())
            {
                var cluster = ((string)enumerator.Current).AsSpan();
                cluster.CopyTo(chars.Slice(position - cluster.Length));
                position -= cluster.Length;
            }
        });
    }

Es gibt eine noch bessere Möglichkeit, eine Methode der StringInfo-Klasse zu verwenden, die viele String-Zuweisungen durch den Enumerator überspringt, indem nur die Indizes zurückgegeben werden.

private static string ReverseString(string str)
    {
        return string.Create(str.Length, str, (chars, state) =>
        {
            var position = 0;
            var indexes = StringInfo.ParseCombiningCharacters(state); // skips string creation
            var stateSpan = state.AsSpan();
            for (int len = indexes.Length, i = len - 1; i >= 0; i--)
            {
                var index = indexes[i];
                var spanLength = i == len - 1 ? state.Length - index : indexes[i + 1] - index;
                stateSpan.Slice(index, spanLength).CopyTo(chars.Slice(position));
                position += spanLength;
            }
        });
    }

Einige Benchmarks im Vergleich zur LINQ-Lösung:

String length 20:

LINQ                       Mean: 2,355.5 ns   Allocated: 1440 B
string.Create              Mean:   851.0 ns   Allocated:  720 B
string.Create with indexes Mean:   466.4 ns   Allocated:  168 B

String length 450:

LINQ                          Mean: 34.33 us   Allocated: 22.98 KB
string.Create                 Mean:   19.13 us   Allocated: 14.98 KB
string.Create with indexes    Mean:   10.32 us   Allocated: 2.69 KB
1
SET

hier ist eine Unicode-sichere Version der Funktion, die als Erweiterung geschrieben wurde, die Unicode sicher handhabt. Es befindet sich in der Nähe der markierten vollständigen Antwort, löst jedoch keine Ausnahmen für "Ungültiges hohes Ersatzzeichen" aus.

public static class StringExtensions
{
    public static string Reverse(this string s)
    {
        var info = new StringInfo(s);
        var charArray = new char[s.Length];
        var teIndices = StringInfo.ParseCombiningCharacters(s).Reverse();

        int j = 0;
        foreach(var i in  teIndices)
        {
            if (char.IsHighSurrogate(s[i]))
            {
                charArray[j] = s[i];
                j++;
                charArray[j] = s[i+1];
            }
            else
            {
                charArray[j] = s[i];
            }
            j++;
        }

        return new string(charArray);

    }
}
1
Jim

So einfach ist das:

string x = "your string";       
string x1 = "";
for(int i = x.Length-1 ; i >= 0; i--)
    x1 += x[i];
Console.WriteLine("The reverse of the string is:\n {0}", x1);

Siehe Ausgabe .

1
Raktim Biswas
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;
        }

schneller als oben

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);
        }
1
vikas

Verwendung der LINQ-Aggregatfunktion

string s = "Karthik U";
s = s.Aggregate(new StringBuilder(), (o, p) => o.Insert(0, p)).ToString();
1
Karthik

Zunächst müssen Sie verstehen, dass str + = die Größe Ihres String-Speichers ändert, um Platz für 1 zusätzliches Zeichen zu schaffen. Dies ist in Ordnung, aber wenn Sie beispielsweise ein Buch mit 1000 Seiten haben, das Sie umkehren möchten, dauert die Ausführung sehr lange.

Die Lösung, die einige Leute vorschlagen könnten, ist die Verwendung von StringBuilder. Wenn Sie ein + = ausführen, weist der Stringbuilder viel größere Speicherbereiche für das neue Zeichen zu, sodass keine Neuzuweisung bei jedem Hinzufügen eines Zeichens erforderlich ist.

Wenn Sie wirklich eine schnelle und minimale Lösung wünschen, würde ich Folgendes vorschlagen:

            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);

In dieser Lösung gibt es eine anfängliche Speicherzuweisung, wenn das Zeichen [] initialisiert wird, und eine Zuweisung, wenn der Zeichenfolgenkonstruktor die Zeichenfolge aus dem Zeichenfolgenarray erstellt.

Auf meinem System habe ich einen Test für Sie durchgeführt, der eine Zeichenfolge von 2 750 000 Zeichen umkehrt. Hier sind die Ergebnisse für 10 Hinrichtungen:

StringBuilder: 190K - 200K Ticks

Char Array: 130K - 160K Ticks

Ich habe auch einen Test für normalen String + = durchgeführt, ihn aber nach 10 Minuten ohne Ausgabe abgebrochen.

Mir ist jedoch auch aufgefallen, dass der StringBuilder für kleinere Zeichenfolgen schneller ist, sodass Sie die Implementierung anhand der Eingabe festlegen müssen.

Prost

1
Reasurria
public static string Reverse2(string x)
        {
            char[] charArray = new char[x.Length];
            int len = x.Length - 1;
            for (int i = 0; i <= len; i++)
                charArray[i] = x[len - i];
            return new string(charArray);
        }
1
Shrini
    string original = "Stack Overflow";
    string reversed = new string(original.Reverse().ToArray());
0
static void Main(string[] args)
{
    string str = "";
    string reverse = "";
    Console.WriteLine("Enter the value to reverse");
    str = Console.ReadLine();
    int length = 0;
    length = str.Length - 1;
    while(length >= 0)
    {
        reverse = reverse + str[length];
        length--;
    }
    Console.Write("Reverse string is {0}", reverse);
    Console.ReadKey();
}
0
Deep
     using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {     
        public static string ReverseString(string str)
        {
            int totalLength = str.Length;
            int iCount = 0;
            string strRev = string.Empty;
            iCount = totalLength;
            while (iCount != 0)
            {
                iCount--;
                strRev += str[iCount]; 
            }
            return strRev;
        }
        static void Main(string[] args)
        {
            string str = "Punit Pandya";
            string strResult = ReverseString(str);
            Console.WriteLine(strResult);
            Console.ReadLine();
        }
    }

  }
0
Punit Pandya

Es gibt verschiedene Möglichkeiten, die Saite umzukehren. Ich habe 3 davon unten gezeigt.

- Verwenden der Array.Reverse-Funktion.

 private static string ReverseString1(string text)
    {
        char[] rtext = text.ToCharArray();
        Array.Reverse(rtext);
        return new string(rtext);
    }

- nur mit String

  private static string ReverseString2(string text)
    {
        String rtext = "";
        for (int i = text.Length - 1; i >= 0; i--)
        {
            rtext = rtext + text[i];
        }
        return rtext;
    }

- Verwenden Sie nur char array

 public static string ReverseString3(string str)
    {
        char[] chars = str.ToCharArray();
        char[] rchars = new char[chars.Length];
        for (int i = 0, j = str.Length - 1; i < chars.Length; i++, j--)
        {
            rchars[j] = chars[i];
        }
        return new string(rchars);
    }
0
Munavvar

Eine ähnliche Frage wurde mir im Interview gestellt. Dies war meine Antwort, obwohl sie wahrscheinlich nicht so schnell ist wie andere Antworten. Meine Frage lautete wie folgt:

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

namespace BackwardsTest
{
    class PrintBackwards
    {
        public static void print(string param)
        {
            if (param == null || param.Length == 0)
            {
                Console.WriteLine("string is null");
                return;
            }
            List<char> list = new List<char>();
            string returned = null;
            foreach(char d in param)
            {
                list.Add(d);
            }
            for(int i = list.Count(); i > 0; i--)
            {
                returned = returned + list[list.Count - 1];
                list.RemoveAt(list.Count - 1);
            }
            Console.WriteLine(returned);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            string test = "I want to print backwards";
            PrintBackwards.print(test);
            System.Threading.Thread.Sleep(5000);
        }
    }
}
0
simon