Comment inverser une simple chaîne dans Go?
Comment inverser une simple chaîne dans Go?
Réponses:
Dans Go1, la rune est un type intégré.
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, sur la liste de diffusion Golang-Nuts , suggère
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)
?
Cela fonctionne, sans tous les soucis avec les fonctions:
func Reverse(s string) (result string) {
for _,v := range s {
result = string(v) + result
}
return
}
Cela fonctionne sur les chaînes Unicode en considérant 2 choses:
Alors voilà:
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
puis plierais le pour en une seule ligne for _, c:=range s { o[i--]=c; }
. Man I HATE the for sans parenthèses - est-ce permis:for(_, c:=range s) { o[i--]=c; }
Des exemples de projets Go: golang / exemple / stringutil / reverse.go , par 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 pour inverser une chaîne
Après avoir inversé la chaîne "bròwn", le résultat correct devrait être "nwòrb" et non "nẁorb".
Notez la tombe au-dessus de la lettre o.
Pour préserver la combinaison de caractères Unicode tels que "as⃝df̅" avec le résultat inverse "f̅ds⃝a",
veuillez vous référer à un autre code répertorié ci-dessous:
J'ai remarqué cette question lorsque Simon a posté sa solution qui, puisque les chaînes sont immuables, est très inefficace. Les autres solutions proposées sont également imparfaites; ils ne fonctionnent pas ou ils sont inefficaces.
Voici une solution efficace qui fonctionne, sauf lorsque la chaîne n'est pas valide UTF-8 ou que la chaîne contient des caractères de combinaison.
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)
cela ne fonctionne pas dans tous les cas.
Il y a trop de réponses ici. Certains d'entre eux sont clairement des doublons. Mais même à partir de celle de gauche, il est difficile de sélectionner la meilleure solution.
J'ai donc parcouru les réponses, jeté celle qui ne fonctionne pas pour unicode et également supprimé les doublons. J'ai comparé les survivants pour trouver le plus rapide. Voici donc les résultats avec attribution (si vous remarquez les réponses que j'ai manquées, mais qui valent la peine d'être ajoutées, n'hésitez pas à modifier le benchmark):
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
Voici donc la méthode la plus rapide de 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)
}
Pour une raison quelconque, je ne peux pas ajouter de benchmark, vous pouvez donc le copier à partir de PlayGround(vous ne pouvez pas y exécuter de tests). Renommez-le et exécutezgo test -bench=.
J'ai écrit la Reverse
fonction suivante qui respecte l'encodage UTF8 et les caractères combinés:
// 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)
}
J'ai fait de mon mieux pour le rendre aussi efficace et lisible que possible. L'idée est simple, parcourez les runes à la recherche de caractères combinés, puis inversez les runes des personnages combinés sur place. Une fois que nous les avons tous couverts, inversez les runes de la chaîne entière également en place.
Supposons que nous souhaitons inverser cette chaîne bròwn
. Le ò
est représenté par deux runes, une pour le o
et un pour cet unicode \u0301a
qui représente la «tombe».
Pour plus de simplicité, représentons la chaîne comme ceci bro'wn
. La première chose que nous faisons est de rechercher des caractères combinés et de les inverser. Alors maintenant, nous avons la chaîne br'own
. Enfin, nous inversons toute la chaîne et finissons par nwo'rb
. Ceci nous est retourné commenwòrb
Vous pouvez le trouver ici https://github.com/shomali11/util si vous souhaitez l'utiliser.
Voici quelques cas de test pour montrer quelques scénarios différents:
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")
}
S'appuyant sur la suggestion originale de Stephan202, et semble fonctionner pour les chaînes Unicode:
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, "" );
}
Alternatif, n'utilisant pas de package de chaînes, mais pas '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 );
}
//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
Utilisation de chaînes.Builder est environ 3 fois plus rapide que l'utilisation de la concaténation de chaînes
Voici une approche assez différente, je dirais plus fonctionnelle, non répertoriée parmi d'autres réponses:
func reverse(s string) (ret string) {
for _, v := range s {
defer func(r rune) { ret += string(r) }(v)
}
return
}
ret
est maintenue en fermeture pour un traitement ultérieur, par chaque fonction de report.
C'est la mise en œuvre la plus rapide
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)
}
}
Ce code préserve les séquences de combinaison de caractères intactes et devrait également fonctionner avec une entrée UTF-8 non valide.
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)
}
Cela pourrait être un peu plus efficace si les primitives unicode / norm permettaient d'itérer à travers les limites d'une chaîne sans allouer. Voir également https://code.google.com/p/go/issues/detail?id=9055 .
[]byte
en string
Go, remplace «entrée UTF-8 non valide» par un point de code valide \uFFFD
.
string
n'existe pas. Mais il peut exister dans un fichier []byte
.
Si vous avez besoin de gérer des clusters de graphèmes, utilisez le module unicode ou regexp.
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
sortie est citée, elle modifie la citation principale!
Vous pouvez également importer une implémentation existante:
import "4d63.com/strrev"
Ensuite:
strrev.Reverse("abåd") // returns "dåba"
Ou pour inverser une chaîne comprenant des caractères combinant unicode:
strrev.ReverseCombining("abc\u0301\u031dd") // returns "d\u0301\u031dcba"
Ces implémentations prennent en charge l'ordre correct des caractères multi-octets Unicode et le peignage des caractères lorsqu'ils sont inversés.
Remarque: les fonctions d'inversion de chaîne intégrées dans de nombreux langages de programmation ne préservent pas la combinaison, et l'identification des caractères de combinaison nécessite beaucoup plus de temps d'exécution.
Ce n'est certainement pas la solution la plus efficace en termes de mémoire, mais pour une solution sûre UTF-8 "simple", ce qui suit fera le travail et ne cassera pas les runes.
C'est à mon avis le plus lisible et le plus compréhensible de la page.
func reverseStr(str string) (out string) {
for _, s := range str {
out = string(s) + out
}
return
}
Les deux méthodes suivantes fonctionnent plus rapidement que la solution la plus rapide qui préserve la combinaison de caractères , même si cela ne veut pas dire que je manque quelque chose dans ma configuration de référence.
//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
Deuxième méthode inspirée de cela
//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
REMARQUE: Cette réponse date de 2009, il existe donc probablement de meilleures solutions à l'heure actuelle.
Cela semble un peu «rond-point», et probablement pas très efficace, mais illustre comment l'interface de Reader peut être utilisée pour lire des chaînes. Les IntVectors semblent également très appropriés comme tampons lorsque vous travaillez avec des chaînes utf8.
Ce serait encore plus court si vous omettiez la partie `` taille '' et l'insertion dans le vecteur par Insertion, mais je suppose que ce serait moins efficace, car le vecteur entier doit alors être repoussé de un à chaque fois qu'une nouvelle rune est ajoutée .
Cette solution fonctionne définitivement avec les caractères utf8.
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());
}
Une version qui, je pense, fonctionne sur unicode. Il est construit sur les fonctions 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);
}
la rune est un type, alors utilisez-la. De plus, Go n'utilise pas de points-virgules.
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))
}
essayez ci-dessous le 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"))
}
pour plus d'informations, consultez http://golangcookbook.com/chapters/strings/reverse/
et http://www.dotnetperls.com/reverse-string-go
Pour les chaînes simples, il est possible d'utiliser une telle construction:
func Reverse(str string) string {
if str != "" {
return Reverse(str[1:]) + str[:1]
}
return ""
}
Voici encore une autre solution:
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)
}
Cependant, la solution de yazu ci-dessus est plus élégante car il inverse la []rune
tranche en place.
Encore une autre solution (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, "")
}
Tester
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)
}
}
Production
Input: GO je úžasné!
Output: !énsažú ej OG
PASS
ok github.com/alesr/reverse-string 0.098s
a+´
au lieu deá
. Je me demande comment cela pourrait être pris en compte, sans le normaliser.