it-swarm.com.de

Wie kann man eine Zeichenfolge in Go umkehren?

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

79
user211499

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)
}
71
yazu

Russ Cox, auf der Liste der Golang-Nuts , 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)
}
45
user181548

Dies funktioniert, ohne all das mit Funktionen zu tun:

func Reverse(s string) (result string) {
  for _,v := range s {
    result = string(v) + result
  }
  return 
}
20
Simon

Dies funktioniert bei Unicode-Strings unter Berücksichtigung von 2 Dingen:

  • range funktioniert bei Zeichenfolgen, indem Unicode-Zeichen aufgelistet werden
  • zeichenfolge kann aus int-Segmenten erstellt werden, bei denen jedes Element ein Unicode-Zeichen ist.

So geht es also:

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

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

Go Playground für einen String umkehren

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


Um Unicode zu erhalten, kombinieren Sie Zeichen wie "as⃝df̅" mit dem umgekehrten Ergebnis "f̅ds⃝a".
Bitte beziehen Sie sich auf einen anderen Code, der unten aufgeführt ist: 

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

11
Ivan Chau

Diese Frage ist mir aufgefallen, als Simonseine Lösung gepostet hat, die da Strings sind unveränderlich, ist sehr ineffizient. Die anderen vorgeschlagenen Lösungen sind ebenfalls fehlerhaft. Sie funktionieren nicht oder sind ineffizient.

Hier ist eine effiziente Lösung, die funktioniert, außer wenn die Zeichenfolge nicht UTF-8-gültig ist oder kombinierte Zeichen enthält.

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 犬")))
}
11
peterSO

Hier gibt es zu viele Antworten. Einige von ihnen sind eindeutige Duplikate. Aber auch von der linken Seite 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 bemerken, die ich verpasst habe, aber es lohnt sich hinzuzufügen, können Sie den Benchmark gerne modifizieren):

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, von dem Sie ihn kopieren können PlayGround (Sie können dort keine Tests durchführen). Benenne es um und starte go test -bench=.

6
Salvador Dali

Ich habe die folgende Reverse-Funktion 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 gegeben, um es so effizient und lesbar wie möglich zu machen. Die Idee ist einfach: Durchqueren Sie die Runen und suchen Sie nach kombinierten Charakteren. Dann kehren Sie die Runen der kombinierten Charaktere an Ort und Stelle um. Wenn wir sie alle besprochen haben, vertauschen Sie die Runen der gesamten Saite auch an Ort und Stelle.

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

Der Einfachheit halber wollen wir die Zeichenfolge wie folgt bro'wn darstellen. Als erstes suchen wir nach kombinierten Charakteren und kehren sie um. Jetzt haben wir den String br'own. Zum Schluss kehren wir den gesamten String um und enden mit nwo'rb. Diese wird als nwòrb an uns zurückgesandt.

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

Hier sind einige Testfälle, die verschiedene Szenarien 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")
}
5
Raed Shomali

Wenn Sie mit Graphem-Clustern arbeiten 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
}
3
masakielastic

Bauen auf dem ursprünglichen Vorschlag von Stephan202 auf 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, aber nicht "Unicode-Safe":

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 );
}
3
martin clayton

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)
    }
}
3
rmuller

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 Anordnung von Unicode-Multibyte- und Kämmungszeichen, wenn sie umgekehrt werden.

Hinweis: In vielen Programmiersprachen sind die Funktionen zum Umkehren von Zeichenfolgen nicht enthalten. Das Erkennen von Zeichenkombinationen erfordert erheblich mehr Ausführungszeit.

2
Leigh McCulloch

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

Es wäre noch kürzer, wenn Sie den 'size'-Teil weglassen und durch Einfügen in den Vektor einfügen, aber ich denke, das wäre weniger effizient, da der gesamte Vektor bei jedem Hinzufügen einer neuen Rune 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());
}
2
Oliver Mason

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

Es ist meiner Meinung nach das lesbarste und verständlichste auf der Seite.

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

    return
}
2
donatJ

Die folgenden zwei Methoden laufen schneller als die schnellste Lösung, die kombinierende Zeichen beibehält , obwohl das nicht heißt, dass mir etwas in meinem Benchmark-Setup 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 von this

//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
1
Sridhar

Dieser Code behält Folgen von kombinierten Zeichen bei, und .__ sollte auch mit ungültiger UTF-8-Eingabe 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-Primitive Das Durchlaufen der Grenzen eines Strings ohne Zuweisung zulassen. Siehe auch https://code.google.com/p/go/issues/detail?id=9055 .

1
rog

Für einfache Zeichenketten ist es möglich, eine solche Konstruktion zu verwenden:

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

versuchen Sie es mit dem folgenden Code:

package main

import "fmt"

func reverse(s string) string {
    chars := []rune(s)
    for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
        chars[i], chars[j] = chars[j], chars[i]
    }
    return string(chars)
}

func main() {
    fmt.Printf("%v\n", reverse("abcdefg"))
}

weitere Informationen finden Sie unter http://golangcookbook.com/chapters/strings/reverse/
und http://www.dotnetperls.com/reverse-string-go

1
Bunker Boy

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))
}
1
Walter

Eine Version, von der ich denke, dass sie für Unicode funktioniert. Es basiert auf den utf8.Rune-Funktionen:

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

Hier ist etwas ganz anderes, ich würde sagen, mehr funktionalen 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
}

Credits

1
Vladimir Bauer
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
0

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)
}
0
OneOfOne
    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
    }
0
saurabh

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 []rune-Scheibe an ihrem Platz umkehrt.

0
Jabba