Comment pouvons-nous inverser une chaîne simple dans Go?
Dans Go1, 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)
}
Cela fonctionne, sans tout le foutoir 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);
}
De Aller aux exemples de projets: 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 doit être "nwòrb" et non "nẁorb".
Notez la sépulture au-dessus de la lettre o.
Pour conserver Unicode combinant des caractères tels que "as⃝df̅" avec le résultat inverse "f̅ds⃝a",
s'il vous plaît se référer à un autre code énuméré ci-dessous:
J'ai remarqué cette question lorsque Simon posted sa solution qui, comme les chaînes sont immuables, est très inefficace. Les autres solutions proposées sont également défectueuses. ils ne travaillent 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 犬")))
}
Il y a trop de réponses ici. Certains d'entre eux sont des doublons clairs. Mais même à gauche, il est difficile de choisir la meilleure solution.
J'ai donc parcouru les réponses, jeté celle qui ne fonctionne pas pour Unicode et supprimé les doublons. J'ai comparé les survivants pour trouver le plus rapide. Donc voici les résultats avec attribution (si vous remarquez les réponses que j'ai manquées, mais que vous pouvez ajouter, n'hésitez pas à modifier le point de repère):
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
Donc voici 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 repère, vous pouvez donc le copier à partir de PlayGround (vous ne pouvez pas y exécuter de tests). Renommez-le et lancez go test -bench=.
J'ai écrit la fonction Reverse
suivante qui respecte le codage 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 en place. Une fois que nous avons tout couvert, inversez les runes de la chaîne entière également en place.
Disons que nous aimerions inverser cette chaîne bròwn
. Le ò
est représenté par deux runes, une pour la o
et une pour ce unicode \u0301a
qui représente la "tombe".
Pour plus de simplicité, représentons la chaîne comme ceci bro'wn
. La première chose à faire est de rechercher les caractères combinés et de les inverser. Nous avons maintenant la chaîne br'own
. Enfin, nous inversons la chaîne entière et finissons par nwo'rb
. Ceci nous est retourné sous la forme nwòrb
Vous pouvez le trouver ici https://github.com/shomali11/util si vous souhaitez l’utiliser.
Voici quelques cas de test pour illustrer deux 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")
}
Si vous devez gérer des grappes 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
}
S'appuyant sur la suggestion initiale 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, "" );
}
Autre solution, n'utilisez pas de paquet 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 );
}
C'est l'implémentation 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)
}
}
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 de combinaison Unicode:
strrev.ReverseCombining("abc\u0301\u031dd") // returns "d\u0301\u031dcba"
Ces implémentations prennent en charge le tri correct des caractères multi-octets et de combinaison de caractères unicode lorsqu’ils sont inversés.
Remarque: Les fonctions d'inversion de chaîne intégrées à de nombreux langages de programmation ne préservent pas la combinaison, et l'identification de la combinaison de caractères nécessite un temps d'exécution considérablement plus long.
Cela semble un peu «rond-point», et probablement pas très efficace, mais illustre comment l’interface Reader peut être utilisée pour lire des chaînes. IntVectors semble également très approprié comme tampon lorsque vous travaillez avec des chaînes utf8.
Il serait encore plus court en laissant de côté la partie 'taille' et l'insertion dans le vecteur par Insert, mais j'imagine que ce serait moins efficace, car le vecteur entier doit alors être repoussé de un à chaque nouvelle rangé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());
}
Ce n’est assurément pas la solution la plus efficace en termes de mémoire, mais pour une solution "simple" sans danger pour UTF-8, les tâches suivantes seront accomplies et ne casseront 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 conserve la combinaison de caractères , même si cela ne veut pas dire que quelque chose me manque 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 par 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
Ce code conserve intactes les séquences de combinaison de caractères, 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/norme Permettaient de parcourir les limites d’une chaîne sans Voir aussi https://code.google.com/p/go/issues/detail?id=9055 .
Pour des 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 ""
}
essayez le code ci-dessous:
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
rune est un type, utilisez-le. 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))
}
Une version qui, à mon avis, 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);
}
Voici une approche très différente, je dirais plus fonctionnelle, qui ne figure pas parmi les autres réponses
func reverse(s string) (ret string) {
for _, v := range s {
defer func(r rune) { ret += string(r) }(v)
}
return
}
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, "")
}
Test
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)
}
}
Sortie
Input: GO je úžasné!
Output: !énsažú ej OG
PASS
ok github.com/alesr/reverse-string 0.098s
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)
}
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
}
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 ci-dessus de Yazu est plus élégante car il inverse la tranche []rune
en place.