Wie können wir eine einfache Zeichenfolge in Go umkehren?
Wie können wir eine einfache Zeichenfolge in Go umkehren?
Antworten:
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)
}
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)
}
rune:=[]rune(input)
?
Dies funktioniert, ohne sich um Funktionen zu kümmern:
func Reverse(s string) (result string) {
for _,v := range s {
result = string(v) + result
}
return
}
Dies funktioniert bei Unicode-Zeichenfolgen, indem zwei Dinge berücksichtigt werden:
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);
}
i:=len(o)-1
das 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; }
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:
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 犬")))
}
return string(runes)
funktioniert nicht in allen Fällen.
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=.
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 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 o
und 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")
}
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 );
}
//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
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
}
ret
von jeder Verzögerungsfunktion für die weitere Verarbeitung geschlossen bleibt.
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)
}
}
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 .
[]byte
in " string
Go" wird "ungültige UTF-8-Eingabe" durch einen gültigen Codepunkt ersetzt \uFFFD
.
string
nicht existiert. Aber es kann in einem existieren []byte
.
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
}
str
die Ausgabe in Anführungszeichen gesetzt wird, ändert sich das führende Anführungszeichen!
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.
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
}
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
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());
}
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);
}
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))
}
Versuchen Sie den 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
Für einfache Saiten kann eine solche Konstruktion verwendet werden:
func Reverse(str string) string {
if str != "" {
return Reverse(str[1:]) + str[:1]
}
return ""
}
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 Ort und Stelle umkehrt .
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)
}
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
a+´
stattá
. Ich frage mich, wie das berücksichtigt werden könnte, ohne es zu normalisieren.