Wie kann man einen String in Go umkehren?

100

Wie können wir eine einfache Zeichenfolge in Go umkehren?

user211499
quelle
1
Soweit ich weiß, funktionieren die unten angegebenen Lösungen nicht mit vorkomponierten oder kombinierten Zeichen, wie Geben a+´statt á. Ich frage mich, wie das berücksichtigt werden könnte, ohne es zu normalisieren.
Siritinga
Wenn Sie mit einer Vielzahl ähnlicher Antworten verwechselt werden, überprüfen Sie meinen Benchmark .
Salvador Dali

Antworten:

94

In Go1 ist Rune ein eingebauter Typ.

func Reverse(s string) string {
    runes := []rune(s)
    for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
        runes[i], runes[j] = runes[j], runes[i]
    }
    return string(runes)
}
yazu
quelle
4
Sie können len () in Go nicht verwenden, um die Länge eines Strings / Arrays / Slice usw. herauszufinden. Warum? - len () in Go bedeutet die Größe der Eingabe in Bytes. Es entspricht nicht seiner Länge. - Nicht alle Runen von utf8 sind gleich groß. Es kann entweder 1, 2, 4 oder 8 sein. - Sie sollten die Methode RuneCountInString des Unicode / ut8-Pakets verwenden, um die Länge der Rune zu ermitteln.
Anvesh Checka
14
@AnveshChecka, das ist falsch. Siehe golang.org/pkg/builtin/#len - len () auf einem Slice gibt definitiv die Anzahl der Elemente zurück, nicht die Größe in Bytes. Ein Stück Runen ist der richtige Weg, dies zu tun.
Chowey
3
@ рытфолд Dies funktioniert nicht beim Kombinieren von Zeichen. Siehe play.golang.org/p/sBgZAV7gCb , der kombinierende Charakter wird nicht mit seiner Basis ausgetauscht.
Chowey
53

Russ Cox, auf der Mailingliste der Golang-Nüsse , schlägt vor

package main 
import "fmt"
func main() { 
        input := "The quick brown 狐 jumped over the lazy 犬" 
        // Get Unicode code points. 
        n := 0
        rune := make([]rune, len(input))
        for _, r := range input { 
                rune[n] = r
                n++
        } 
        rune = rune[0:n]
        // Reverse 
        for i := 0; i < n/2; i++ { 
                rune[i], rune[n-1-i] = rune[n-1-i], rune[i] 
        } 
        // Convert back to UTF-8. 
        output := string(rune)
        fmt.Println(output)
}
Benutzer181548
quelle
20
Mir gefällt, wie sie dich zwingen, über Kodierungen nachzudenken.
György Andrasek
9
Off-Topic: Warum ist es [Golang-Nüsse] und nicht [Go-Nuts]?
Jimmy
2
Wow, wtf hat beim Rückwärtsfahren die doppelte Zuordnung? Interessant. Denken Sie jetzt an eine Saite mit einer ungeraden Anzahl von Runen. Der mittlere wird speziell behandelt, mit dem richtigen Endergebnis. :) Eine interessante kleine Optimierung, an die ich nicht sofort gedacht hätte.
Kissaki
4
Ich verstehe nicht, warum diese Umwandlung in Rune, warum nicht rune:=[]rune(input)?
Siritinga
1
Sie benötigen nicht die erste für die Bereichsschleife. Ausgabe: = [] Rune (Eingabe); n: = len (Ausgabe) Und Sie brauchen nicht die Rune = Rune [0: n]
dvallejo
28

Dies funktioniert, ohne sich um Funktionen zu kümmern:

func Reverse(s string) (result string) {
  for _,v := range s {
    result = string(v) + result
  }
  return 
}
Simon
quelle
6
Da es funktioniert, ist es sehr ineffizient, da Zeichenfolgen unveränderlich sind. Ich habe eine effizientere Lösung veröffentlicht.
PeterSO
5
Das ist viel zu leicht zu verstehen. Machen Sie es schwieriger :-) (und "plus eins", um einfach
weiterzumachen
2
Dies ist die beste Antwort, es sei denn, das Umkehren von Zeichenfolgen ist Ihr Engpass.
Banjocat
1
@dolmen - warum sollte dies nicht das Kombinieren von Zeichen behandeln? Ein Bereich in einer Zeichenfolge gibt eine Rune zurück, die ein Codepunkt ist.
Stan R.
1
@StanR. Eine Rune ist keine Glyphe. Eine Glyphe kann aus mehreren Codepunkten / Runen bestehen. Siehe reedbeta.com/blog/programmers-intro-to-unicode/#combining-marks Durch das Umkehren von Codepunkten werden Kombinationsmarkierungen an einen anderen Basiscodepunkt angehängt .
Dolmen
14

Dies funktioniert bei Unicode-Zeichenfolgen, indem zwei Dinge berücksichtigt werden:

  • range arbeitet mit Zeichenfolgen, indem Unicode-Zeichen aufgelistet werden
  • Zeichenfolge kann aus int-Slices erstellt werden, wobei jedes Element ein Unicode-Zeichen ist.

Also los geht's:

func reverse(s string) string {
    o := make([]int, utf8.RuneCountInString(s));
    i := len(o);
    for _, c := range s {
        i--;
        o[i] = c;
    }
    return string(o);
}
Randy Sugianto 'Yuku'
quelle
Ich würde i:=len(o)-1das for zuweisen und dann in eine einzige Zeile falten for _, c:=range s { o[i--]=c; }. Mann, ich hasse das für ohne Klammern - ist das erlaubt:for(_, c:=range s) { o[i--]=c; }
Lawrence Dol
Können Sie erklären, was das _ tut?
Lawrence Dol
6
@ Software_Monkey: o [i--] = c ist in Go nicht erlaubt. - und ++ sind Anweisungen, keine Ausdrücke. _ bedeutet, diese Variable zu verwerfen (zu ignorieren).
Randy Sugianto 'Yuku'
1
Mit go 1.1+ wird ein Fehler in der Zeile string ([] int) zurückgegeben. Wenn stattdessen der
Runentyp
1
@yuku: Immer noch fehlgeschlagen auf s: = "Les Mise \ u0301rables"
Stefan Steiger
13

From Go-Beispielprojekte: golang / example / stringutil / reverse.go von Andrew Gerrand

/*
Copyright 2014 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
     http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Reverse returns its argument string reversed rune-wise left to right.
func Reverse(s string) string {
    r := []rune(s)
    for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
        r[i], r[j] = r[j], r[i]
    }
    return string(r)
}

Gehen Sie auf den Spielplatz, um eine Saite umzukehren

Nach dem Umkehren der Zeichenfolge "bròwn" sollte das korrekte Ergebnis "nwòrb" und nicht "nẁorb" sein.
Beachten Sie das Grab über dem Buchstaben o.


Informationen zum Beibehalten von Unicode-Kombinationszeichen wie "as⃝df̅" mit dem umgekehrten Ergebnis "f̅ds⃝a" finden
Sie in einem anderen unten aufgeführten Code:

http://rosettacode.org/wiki/Reverse_a_string#Go

Ivan Chau
quelle
2
Vielen Dank, dass Sie den Unterschied zu stackoverflow.com/a/10030772/3093387 geklärt haben. Es scheint, dass sich diese beiden Lösungen darin unterscheiden, wie sie mit Zeichenfolgen wie "bròwn" umgehen.
Josliber
Vielen Dank für die Erwähnung der Rosettacode-Lösung, die das Kombinieren von Zeichen übernimmt
Dolmen
11

Ich habe bemerkt , diese Frage , wenn Simon geschrieben seine Lösung , die seit Strings unveränderlich sind, sehr ineffizient ist. Die anderen vorgeschlagenen Lösungen sind ebenfalls fehlerhaft; Sie funktionieren nicht oder sind ineffizient.

Hier ist eine effiziente Lösung, die funktioniert, es sei denn, die Zeichenfolge ist nicht gültig UTF-8 oder die Zeichenfolge enthält kombinierte Zeichen.

package main

import "fmt"

func Reverse(s string) string {
    n := len(s)
    runes := make([]rune, n)
    for _, rune := range s {
        n--
        runes[n] = rune
    }
    return string(runes[n:])
}

func main() {
    fmt.Println(Reverse(Reverse("Hello, 世界")))
    fmt.Println(Reverse(Reverse("The quick brown 狐 jumped over the lazy 犬")))
}
peterSO
quelle
1
return string (runes) Funktioniert auch.
3
@ Tommy: Nein, return string(runes)funktioniert nicht in allen Fällen.
PeterSO
Könnten Sie bitte etwas näher erläutern, warum das so ist? Ich habe ein kurzes Programm gemacht und es funktioniert dort, aber vielleicht werden die Fälle, über die Sie sprechen, dort nicht ausgelöst? play.golang.org/p/yk1sAwFjol
1
@Tommy: Ihr kurzes Programm zeigt lediglich, dass das NUL-Zeichen ein NOP ist, wenn es an einen Drucker oder ein Terminal gesendet wird. Ihre Reverse2-Funktion schlägt für nicht ASCII UTF-8-codierte Zeichenfolgen fehl. Ich habe Ihr Kurzprogramm so überarbeitet, dass es ein gültiger Test ist: play.golang.org/p/Ic5G5QEO93
peterSO
Eine weitere falsche "Lösung", die das Kombinieren von Zeichen nicht richtig handhabt.
Dolmen
9

Hier gibt es zu viele Antworten. Einige von ihnen sind klare Duplikate. Aber selbst von links ist es schwierig, die beste Lösung auszuwählen.

Also ging ich die Antworten durch, warf die weg, die für Unicode nicht funktioniert, und entfernte auch Duplikate. Ich habe die Überlebenden verglichen, um die schnellsten zu finden. Also hier sind die Ergebnisse mit Zuschreibung (wenn Sie die Antworten merken , dass ich verpasst, aber noch hinzugefügt, können Sie den Maßstab ändern):

Benchmark_rmuller-4   100000         19246 ns/op
Benchmark_peterSO-4    50000         28068 ns/op
Benchmark_russ-4       50000         30007 ns/op
Benchmark_ivan-4       50000         33694 ns/op
Benchmark_yazu-4       50000         33372 ns/op
Benchmark_yuku-4       50000         37556 ns/op
Benchmark_simon-4       3000        426201 ns/op

Also hier ist die schnellste Methode von rmuller :

func Reverse(s string) string {
    size := len(s)
    buf := make([]byte, size)
    for start := 0; start < size; {
        r, n := utf8.DecodeRuneInString(s[start:])
        start += n
        utf8.EncodeRune(buf[size-start:], r)
    }
    return string(buf)
}

Aus irgendeinem Grund kann ich keinen Benchmark hinzufügen, sodass Sie ihn kopieren können PlayGround(Sie können dort keine Tests ausführen). Benennen Sie es um und führen Sie es ausgo test -bench=.

Salvador Dali
quelle
Keine dieser "Lösungen" behandelt das korrekte Kombinieren von Marken .
Dolmen
5

Ich habe die folgende ReverseFunktion geschrieben, die die UTF8-Codierung und kombinierte Zeichen berücksichtigt:

// Reverse reverses the input while respecting UTF8 encoding and combined characters
func Reverse(text string) string {
    textRunes := []rune(text)
    textRunesLength := len(textRunes)
    if textRunesLength <= 1 {
        return text
    }

    i, j := 0, 0
    for i < textRunesLength && j < textRunesLength {
        j = i + 1
        for j < textRunesLength && isMark(textRunes[j]) {
            j++
        }

        if isMark(textRunes[j-1]) {
            // Reverses Combined Characters
            reverse(textRunes[i:j], j-i)
        } 

        i = j
    }

    // Reverses the entire array
    reverse(textRunes, textRunesLength)

    return string(textRunes)
}

func reverse(runes []rune, length int) {
    for i, j := 0, length-1; i < length/2; i, j = i+1, j-1 {
        runes[i], runes[j] = runes[j], runes[i]
    }
}

// isMark determines whether the rune is a marker
func isMark(r rune) bool {
    return unicode.Is(unicode.Mn, r) || unicode.Is(unicode.Me, r) || unicode.Is(unicode.Mc, r)
}

Ich habe mein Bestes getan, um es so effizient und lesbar wie möglich zu gestalten. Die Idee ist einfach: Durchlaufen Sie die Runen auf der Suche nach kombinierten Charakteren und kehren Sie dann die Runen der kombinierten Charaktere an Ort und Stelle um. Sobald wir sie alle abgedeckt haben, kehren Sie die Runen der gesamten Saite ebenfalls an Ort und Stelle um.

Angenommen, wir möchten diese Zeichenfolge umkehren bròwn. Das òwird durch zwei Runen dargestellt, eine für die ound eine für diesen Unicode \u0301a, der das "Grab" darstellt.

Lassen Sie uns der Einfachheit halber die Zeichenfolge wie folgt darstellen bro'wn. Als erstes suchen wir nach kombinierten Zeichen und kehren sie um. Jetzt haben wir also die Zeichenfolge br'own. Schließlich kehren wir den gesamten String um und landen bei nwo'rb. Dies wird uns als zurückgegebennwòrb

Sie finden es hier https://github.com/shomali11/util, wenn Sie es verwenden möchten.

Hier sind einige Testfälle, um einige verschiedene Szenarien zu zeigen:

func TestReverse(t *testing.T) {
    assert.Equal(t, Reverse(""), "")
    assert.Equal(t, Reverse("X"), "X")
    assert.Equal(t, Reverse("b\u0301"), "b\u0301")
    assert.Equal(t, Reverse("😎⚽"), "⚽😎")
    assert.Equal(t, Reverse("Les Mise\u0301rables"), "selbare\u0301siM seL")
    assert.Equal(t, Reverse("ab\u0301cde"), "edcb\u0301a")
    assert.Equal(t, Reverse("This `\xc5` is an invalid UTF8 character"), "retcarahc 8FTU dilavni na si `�` sihT")
    assert.Equal(t, Reverse("The quick bròwn 狐 jumped over the lazy 犬"), "犬 yzal eht revo depmuj 狐 nwòrb kciuq ehT")
}
Raed Shomali
quelle
3

Aufbauend auf Stephan202s ursprünglichem Vorschlag und scheint für Unicode-Strings zu funktionieren:

import "strings";

func Reverse( orig string ) string {
    var c []string = strings.Split( orig, "", 0 );

    for i, j := 0, len(c)-1; i < j; i, j = i+1, j-1 {
        c[i], c[j] = c[j], c[i]
    }

    return strings.Join( c, "" );
}

Alternativ, kein String-Paket verwendet, aber nicht "Unicode-sicher":

func Reverse( s string ) string {
    b := make([]byte, len(s));
    var j int = len(s) - 1;
    for i := 0; i <= j; i++ {
        b[j-i] = s[i]
    }

    return string ( b );
}
Martin Clayton
quelle
+1. Das funktioniert. Aber ich muss sagen, dass es (vorerst) ziemlich seltsam ist, dass das Teilen und Verbinden für eine so einfache Aufgabe notwendig ist ...
Stephan202
@martin: Entschuldigung für die Bearbeitung. Ich habe versehentlich meine aktualisierte Antwort in Ihre Frage eingefügt ... ich schäme mich sehr .
Stephan202
@Stephan - kein Problem. Ich habe eine alternative Lösung hinzugefügt, die auf der Bytes-Funktion des Zeichenfolgenpakets basiert.
Martin Clayton
@Nosradena: Ich rollte innerhalb derselben Minute zurück (ich war überrascht zu sehen, dass Martin seine Antwort mit genau dem Text aktualisierte, den ich gerade geschrieben hatte ... und dann dämmerte es mir;)
Stephan202
@martin: die zweite version sieht besser aus wenn du mich fragst :)
Stephan202
3
//Reverse reverses string using strings.Builder. It's about 3 times faster
//than the one with using a string concatenation
func Reverse(in string) string {
    var sb strings.Builder
    runes := []rune(in)
    for i := len(runes) - 1; 0 <= i; i-- {
        sb.WriteRune(runes[i])
    }
    return sb.String()
}


//Reverse reverses string using string
func Reverse(in string) (out string) {
    for _, r := range in {
        out = string(r) + out
    }
    return
}

BenchmarkReverseStringConcatenation-8   1000000 1571 ns/op  176 B/op    29 allocs/op
BenchmarkReverseStringsBuilder-8        3000000 499 ns/op   56 B/op 6 allocs/op

Die Verwendung von Strings.Builder ist etwa dreimal schneller als die Verwendung von String-Verkettung

Vlad Bezden
quelle
1
Ich frage mich, warum diese Frage trotz der genauesten Antwort keine positiven Stimmen hat
Nilesh
3

Hier ist ganz anders, ich würde sagen, eher funktionaler Ansatz, nicht unter anderen Antworten aufgeführt:

func reverse(s string) (ret string) {
    for _, v := range s {
        defer func(r rune) { ret += string(r) }(v)
    }
    return
}
Vladimir Bauer
quelle
Ich bin mir ziemlich sicher, dass dies nicht die schnellste Lösung ist, aber es zeigt, wie die Rückgabevariable retvon jeder Verzögerungsfunktion für die weitere Verarbeitung geschlossen bleibt.
Vladimir Bauer
Langsam und behandelt das Kombinieren von Zeichen nicht richtig.
Dolmen
1
Ich bin mir nicht sicher, wie schnell das geht, aber es ist wunderschön.
donatJ
Die Leistung dieses Modells kann in Go 1.14 verbessert werden. Mindestens Release Notes Anspruch Null - Overhead von Zurückstellungs zu haben.
Vladimir Bauer
2

Dies ist die schnellste Implementierung

func Reverse(s string) string {
    size := len(s)
    buf := make([]byte, size)
    for start := 0; start < size; {
        r, n := utf8.DecodeRuneInString(s[start:])
        start += n
        utf8.EncodeRune(buf[size-start:], r)
    }
    return string(buf)
}

const (
    s       = "The quick brown 狐 jumped over the lazy 犬"
    reverse = "犬 yzal eht revo depmuj 狐 nworb kciuq ehT"
)

func TestReverse(t *testing.T) {
    if Reverse(s) != reverse {
        t.Error(s)
    }
}

func BenchmarkReverse(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Reverse(s)
    }
}
Müller
quelle
Haben Sie die Lösungen verglichen, bevor Sie behaupteten, es sei die schnellste Implementierung?
Denys Séguret
Ja, das ist der Grund, warum der BenchmarkReverse-Code vorhanden ist :). Allerdings habe ich die Ergebnisse nicht mehr.
Müller
Schnelle Lösung, aber immer noch falsch, da die Kombination von Zeichen nicht richtig funktioniert.
Dolmen
Stimmt es, dass @dolmen sagt, dass dies nicht das Kombinieren von Zeichen behandelt? Gibt es hier eine Lösung, die dies tut?
Geraldss
2

Dieser Code behält Sequenzen von kombinierten Zeichen bei und sollte auch mit ungültigen UTF-8-Eingaben funktionieren.

package stringutil
import "code.google.com/p/go.text/unicode/norm"

func Reverse(s string) string {
    bound := make([]int, 0, len(s) + 1)

    var iter norm.Iter
    iter.InitString(norm.NFD, s)
    bound = append(bound, 0)
    for !iter.Done() {
        iter.Next()
        bound = append(bound, iter.Pos())
    }
    bound = append(bound, len(s))
    out := make([]byte, 0, len(s))
    for i := len(bound) - 2; i >= 0; i-- {
        out = append(out, s[bound[i]:bound[i+1]]...)
    }
    return string(out)
}

Es könnte etwas effizienter sein, wenn die Unicode- / Norm-Grundelemente das Durchlaufen der Grenzen eines Strings ohne Zuweisung erlauben. Siehe auch https://code.google.com/p/go/issues/detail?id=9055 .

Rog
quelle
Es gibt keine solche "ungültige UTF-8-Eingabe" in Zeichenfolgenwerten: Beim Konvertieren von []bytein " stringGo" wird "ungültige UTF-8-Eingabe" durch einen gültigen Codepunkt ersetzt \uFFFD.
Dolmen
Ich verstehe den obigen Kommentar nicht. Wollen Sie damit sagen, dass das Verhalten dieses Codes falsch ist, wenn eine Zeichenfolge mit ungültigem UTF-8 angezeigt wird?
Rog
Ich sage, dass ungültiges UTF-8 in einem Go stringnicht existiert. Aber es kann in einem existieren []byte.
Dolmen
Eine Go-Zeichenfolge kann genau so viel ungültiges utf-8 enthalten wie ein [] Byte. Zum Beispiel: play.golang.org/p/PG0I4FJfEN
Rog
2

Wenn Sie Graphemcluster verarbeiten müssen, verwenden Sie das Unicode- oder Regexp-Modul.

package main

import (
  "unicode"
  "regexp"
)

func main() {
    str := "\u0308" + "a\u0308" + "o\u0308" + "u\u0308"
    println("u\u0308" + "o\u0308" + "a\u0308" + "\u0308" == ReverseGrapheme(str))
    println("u\u0308" + "o\u0308" + "a\u0308" + "\u0308" == ReverseGrapheme2(str))
}

func ReverseGrapheme(str string) string {

  buf := []rune("")
  checked := false
  index := 0
  ret := "" 

    for _, c := range str {

        if !unicode.Is(unicode.M, c) {

            if len(buf) > 0 {
                ret = string(buf) + ret
            }

            buf = buf[:0]
            buf = append(buf, c)

            if checked == false {
                checked = true
            }

        } else if checked == false {
            ret = string(append([]rune(""), c)) + ret
        } else {
            buf = append(buf, c)
        }

        index += 1
    }

    return string(buf) + ret
}

func ReverseGrapheme2(str string) string {
    re := regexp.MustCompile("\\PM\\pM*|.")
    slice := re.FindAllString(str, -1)
    length := len(slice)
    ret := ""

    for i := 0; i < length; i += 1 {
        ret += slice[length-1-i]
    }

    return ret
}
masakielastisch
quelle
Ich möchte Ihnen 1'000 Upvotes geben. Alle anderen Implementierungen auf dieser Seite kehren einen STRING falsch um (ein STRING ist KEINE Folge von Zeichen).
Stefan Steiger
Das funktioniert nicht. Wenn Sie die Zeichenfolge doppelt umkehren, erhalten Sie nicht die ursprüngliche Zeichenfolge. Die in diesem Beispiel verwendete führende kombinierte Diaeresis (\ u0308) wird mit vorhergehenden Zeichen kombiniert und erzeugt beim Umkehren einen doppelten Umlaut 'a'. Wenn strdie Ausgabe in Anführungszeichen gesetzt wird, ändert sich das führende Anführungszeichen!
Joshua Kolden
2

Sie können auch eine vorhandene Implementierung importieren:

import "4d63.com/strrev"

Dann:

strrev.Reverse("abåd") // returns "dåba"

Oder um eine Zeichenfolge mit Unicode-Kombinationszeichen umzukehren:

strrev.ReverseCombining("abc\u0301\u031dd") // returns "d\u0301\u031dcba"

Diese Implementierungen unterstützen die korrekte Reihenfolge von Unicode-Multibyte und das Kämmen von Zeichen in umgekehrter Reihenfolge.

Hinweis: Die in vielen Programmiersprachen integrierten Funktionen zum Umkehren von Zeichenfolgen bewahren die Kombination nicht, und das Identifizieren von Kombinationszeichen erfordert erheblich mehr Ausführungszeit.

Leigh McCulloch
quelle
1

Es ist sicherlich nicht die speichereffizienteste Lösung, aber für eine "einfache" UTF-8-sichere Lösung wird das Folgende die Arbeit erledigen und keine Runen brechen.

Es ist meiner Meinung nach das am besten lesbare und verständlichste auf der Seite.

func reverseStr(str string) (out string) {
    for _, s := range str {
        out = string(s) + out
    }

    return
}
donatJ
quelle
1

Die folgenden beiden Methoden laufen schneller als die schnellste Lösung, bei der das Kombinieren von Zeichen erhalten bleibt. Das heißt jedoch nicht, dass mir in meinem Benchmark-Setup etwas fehlt.

//input string s
bs := []byte(s)
var rs string
for len(bs) > 0 {
    r, size := utf8.DecodeLastRune(bs)
    rs += fmt.Sprintf("%c", r)
    bs = bs[:len(bs)-size]
} // rs has reversed string

Zweite Methode inspiriert durch diese

//input string s
bs := []byte(s)
cs := make([]byte, len(bs))
b1 := 0
for len(bs) > 0 {
    r, size := utf8.DecodeLastRune(bs)
    d := make([]byte, size)
    _ = utf8.EncodeRune(d, r)
    b1 += copy(cs[b1:], d)
    bs = bs[:len(bs) - size]
} // cs has reversed bytes
Sridhar
quelle
Folgendes fehlt Ihnen in Ihrem Benchmark: Ihre Lösung ist schneller, da die Kombination von Zeichen nicht erhalten bleibt. Es ist einfach unfair, sie zu vergleichen.
Dolmen
1

HINWEIS: Diese Antwort stammt aus dem Jahr 2009, daher gibt es wahrscheinlich bereits bessere Lösungen.


Sieht ein bisschen "Kreisverkehr" aus und ist wahrscheinlich nicht sehr effizient, zeigt aber, wie die Reader-Oberfläche zum Lesen von Zeichenfolgen verwendet werden kann. IntVectors scheinen auch als Puffer für die Arbeit mit utf8-Strings sehr gut geeignet zu sein.

Es wäre sogar noch kürzer, wenn der Teil 'Größe' weggelassen und durch Einfügen in den Vektor eingefügt würde, aber ich denke, das wäre weniger effizient, da der gesamte Vektor jedes Mal, wenn eine neue Rune hinzugefügt wird, um eins zurückgeschoben werden muss .

Diese Lösung funktioniert definitiv mit utf8-Zeichen.

package main

import "container/vector";
import "fmt";
import "utf8";
import "bytes";
import "bufio";


func
main() {
    toReverse := "Smørrebrød";
    fmt.Println(toReverse);
    fmt.Println(reverse(toReverse));
}

func
reverse(str string) string {
    size := utf8.RuneCountInString(str);
    output := vector.NewIntVector(size);
    input := bufio.NewReader(bytes.NewBufferString(str));
    for i := 1; i <= size; i++ {
        rune, _, _ := input.ReadRune();
        output.Set(size - i, rune);
    }
    return string(output.Data());
}
Oliver Mason
quelle
Warum fügen Sie all diese nachgestellten Semikolons hinzu?
Morteza R
@ olivier-mason Es ist Zeit, etwas über gofmt zu lernen, wenn Sie Go-Code teilen.
Dolmen
1
Diese Antwort war von vor acht Jahren.
Oliver Mason
@OliverMason Es ist nie zu spät, eine unvollständige Lösung zu reparieren (oder zu löschen).
Dolmen
0

Eine Version, die meiner Meinung nach mit Unicode funktioniert. Es basiert auf den Funktionen utf8.Rune:

func Reverse(s string) string {
    b := make([]byte, len(s));
    for i, j := len(s)-1, 0; i >= 0; i-- {
        if utf8.RuneStart(s[i]) {
            rune, size := utf8.DecodeRuneInString(s[i:len(s)]);
            utf8.EncodeRune(rune, b[j:j+size]);
            j += size;
        }
    }
    return string(b);
}
Jonathan Wright
quelle
0

Rune ist ein Typ, also benutze ihn. Außerdem verwendet Go keine Semikolons.

func reverse(s string) string {
    l := len(s)
    m := make([]rune, l)

    for _, c := range s {
        l--
        m[l] = c
    }
    return string(m)
}

func main() {
    str := "the quick brown 狐 jumped over the lazy 犬"
    fmt.Printf("reverse(%s): [%s]\n", str, reverse(str))
}
Walter
quelle
Bei der Veröffentlichung dieser Frage wurden Semikolons verwendet.
OneOfOne
Eine weitere falsche "Lösung", die das Kombinieren von Zeichen nicht richtig handhabt.
Dolmen
0

Für einfache Saiten kann eine solche Konstruktion verwendet werden:

func Reverse(str string) string {
    if str != "" {
        return Reverse(str[1:]) + str[:1]
    }
    return ""   
}
Sergo Kurbanov
quelle
-1

Hier ist noch eine andere Lösung:

func ReverseStr(s string) string {
    chars := []rune(s)
    rev := make([]rune, 0, len(chars))
    for i := len(chars) - 1; i >= 0; i-- {
        rev = append(rev, chars[i])
    }
    return string(rev)
}

Die obige Lösung von yazu ist jedoch eleganter, da er die []runeScheibe an Ort und Stelle umkehrt .

Jabba
quelle
-1

Noch eine andere Lösung (tm):

package main 
import "fmt"

type Runes []rune

func (s Runes) Reverse() (cp Runes) {
    l := len(s); cp = make(Runes, l)
    // i <= 1/2 otherwise it will mess up with odd length strings
    for i := 0; i <= l/2; i++ { 
        cp[i], cp[l-1-i] = s[l-1-i], s[i] 
    }
    return cp
}

func (s Runes) String() string {
    return string(s)
}

func main() { 
    input := "The quick brown 狐 jumped over the lazy 犬 +odd" 
    r := Runes(input)
    output := r.Reverse()
    valid := string(output.Reverse()) == input
    fmt.Println(len(r), len(output), r, output.Reverse(), valid)
}
OneOfOne
quelle
-1
package reverseString

import "strings"

// ReverseString - output the reverse string of a given string s
func ReverseString(s string) string {

    strLen := len(s)

    // The reverse of a empty string is a empty string
    if strLen == 0 {
        return s
    }

    // Same above
    if strLen == 1 {
        return s
    }

    // Convert s into unicode points
    r := []rune(s)

    // Last index
    rLen := len(r) - 1

    // String new home
    rev := []string{}

    for i := rLen; i >= 0; i-- {
        rev = append(rev, string(r[i]))
    }

    return strings.Join(rev, "")
}

Prüfung

package reverseString

import (
    "fmt"
    "strings"
    "testing"
)

func TestReverseString(t *testing.T) {

    s := "GO je úžasné!"
    r := ReverseString(s)

    fmt.Printf("Input: %s\nOutput: %s", s, r)

    revR := ReverseString(r)

    if strings.Compare(s, revR) != 0 {
        t.Errorf("Expecting: %s\n. Got: %s\n", s, revR)
    }
}

Ausgabe

Input: GO je úžasné!
Output: nsažú ej OG
PASS
ok      github.com/alesr/reverse-string 0.098s
Alessandro Resta
quelle
Dies funktioniert, wenn die Eingabe in NFC erfolgt. Aber wie die meisten anderen falschen Lösungen funktioniert es hier nicht mit der Kombination von Zeichen.
Dolmen
-1
    func reverseString(someString string) string {
        runeString := []rune(someString)
        var reverseString string
        for i := len(runeString)-1; i >= 0; i -- {
            reverseString += string(runeString[i])
        }
        return reverseString
    }
Saurabh
quelle