Come possiamo invertire una semplice stringa in Go?
Come possiamo invertire una semplice stringa in Go?
Risposte:
In Go1 la runa è un tipo incorporato.
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, sulla mailing list golang-noci , suggerisce
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)
?
Funziona, senza dover perdere tempo con le funzioni:
func Reverse(s string) (result string) {
for _,v := range s {
result = string(v) + result
}
return
}
Funziona su stringhe Unicode considerando 2 cose:
Quindi eccolo:
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
e poi piegherei il per in una singola riga for _, c:=range s { o[i--]=c; }
. Amico che ODIO il per senza parentesi - è consentito:for(_, c:=range s) { o[i--]=c; }
Dai progetti di esempio Go: golang / example / stringutil / reverse.go , di 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)
}
Vai a Playground per invertire una stringa
Dopo aver invertito la stringa "bròwn", il risultato corretto dovrebbe essere "nwòrb", non "nẁorb".
Nota la tomba sopra la lettera o.
Per preservare Unicode combinando caratteri come "as⃝df̅" con il risultato inverso "f̅ds⃝a",
fare riferimento a un altro codice elencato di seguito:
Ho notato questa domanda quando Simon ha pubblicato la sua soluzione che, poiché le stringhe sono immutabili, è molto inefficiente. Anche le altre soluzioni proposte sono difettose; non funzionano o sono inefficienti.
Ecco una soluzione efficiente che funziona, tranne quando la stringa non è valida UTF-8 o la stringa contiene caratteri combinati.
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)
non funziona per tutti i casi.
Ci sono troppe risposte qui. Alcuni di loro sono chiari duplicati. Ma anche da quello di sinistra è difficile selezionare la soluzione migliore.
Quindi ho esaminato le risposte, buttato via quella che non funziona per Unicode e rimosso anche i duplicati. Ho confrontato i sopravvissuti per trovare il più veloce. Quindi ecco i risultati con l'attribuzione (se noti le risposte che ho perso, ma che vale la pena aggiungere, sentiti libero di modificare il 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
Quindi ecco il metodo più veloce di 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)
}
Per qualche motivo non posso aggiungere un benchmark, quindi puoi copiarlo da PlayGround(non puoi eseguire test lì). Rinominalo ed eseguigo test -bench=.
Ho scritto la seguente Reverse
funzione che rispetta la codifica UTF8 e i caratteri combinati:
// 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)
}
Ho fatto del mio meglio per renderlo il più efficiente e leggibile possibile. L'idea è semplice, attraversa le rune alla ricerca di personaggi combinati, quindi inverti le rune dei personaggi combinati sul posto. Una volta che li abbiamo coperti tutti, invertire anche le rune dell'intera stringa sul posto.
Diciamo che vorremmo invertire questa stringa bròwn
. Il ò
è rappresentato da due rune, una per l' o
unicode e una per questo unicode \u0301a
che rappresenta la "tomba".
Per semplicità, rappresentiamo la stringa in questo modo bro'wn
. La prima cosa che facciamo è cercare caratteri combinati e invertirli. Quindi ora abbiamo la stringa br'own
. Infine, invertiamo l'intera stringa e finiamo con nwo'rb
. Questo ci viene restituito comenwòrb
Puoi trovarlo qui https://github.com/shomali11/util se desideri utilizzarlo.
Ecco alcuni casi di test per mostrare un paio di scenari diversi:
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")
}
Basandosi sul suggerimento originale di Stephan202 e sembra funzionare per le stringhe 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, "" );
}
Alternativo, non utilizzando il pacchetto di stringhe, ma non '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
Utilizzo di stringhe Builder è circa 3 volte più veloce rispetto all'utilizzo della concatenazione di stringhe
Qui è abbastanza diverso, direi un approccio più funzionale, non elencato tra le altre risposte:
func reverse(s string) (ret string) {
for _, v := range s {
defer func(r rune) { ret += string(r) }(v)
}
return
}
ret
viene mantenuta in chiusura per ulteriori elaborazioni, da ogni funzione di differimento.
Questa è l'implementazione più veloce
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)
}
}
Questo codice conserva intatte le sequenze di combinazione dei caratteri e dovrebbe funzionare anche con un input UTF-8 non valido.
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)
}
Potrebbe essere un po 'più efficiente se le primitive unicode / norm consentissero l'iterazione attraverso i confini di una stringa senza allocare. Vedi anche https://code.google.com/p/go/issues/detail?id=9055 .
[]byte
a string
Go, sostituisce "input UTF-8 non valido" con un punto di codice valido \uFFFD
.
string
non esiste. Ma può esistere in un file []byte
.
Se hai bisogno di gestire cluster grapheme, usa il modulo unicode o 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
output è quotato, modifica la citazione iniziale!
Puoi anche importare un'implementazione esistente:
import "4d63.com/strrev"
Poi:
strrev.Reverse("abåd") // returns "dåba"
O per invertire una stringa che include caratteri unicode che combinano:
strrev.ReverseCombining("abc\u0301\u031dd") // returns "d\u0301\u031dcba"
Queste implementazioni supportano il corretto ordinamento dei caratteri unicode multibyte e combing quando sono invertiti.
Nota: le funzioni di inversione delle stringhe integrate in molti linguaggi di programmazione non mantengono la combinazione e l'identificazione dei caratteri di combinazione richiede un tempo di esecuzione notevolmente maggiore.
Sicuramente non è la soluzione più efficiente in termini di memoria, ma per una soluzione sicura UTF-8 "semplice" quanto segue porterà a termine il lavoro e non romperà le rune.
È secondo me il più leggibile e comprensibile della pagina.
func reverseStr(str string) (out string) {
for _, s := range str {
out = string(s) + out
}
return
}
I due metodi seguenti funzionano più velocemente della soluzione più veloce che conserva la combinazione di caratteri , anche se questo non vuol dire che mi manchi qualcosa nella mia configurazione di benchmark.
//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
Secondo metodo ispirato da questo
//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
NOTA: questa risposta è del 2009, quindi probabilmente ci sono soluzioni migliori là fuori ormai.
Sembra un po '"indiretto" e probabilmente non molto efficiente, ma illustra come l'interfaccia di Reader può essere utilizzata per leggere dalle stringhe. Gli IntVector sembrano anche molto adatti come buffer quando si lavora con le stringhe utf8.
Sarebbe ancora più breve quando si tralascia la parte 'size' e l'inserimento nel vettore tramite Inserisci, ma immagino che sarebbe meno efficiente, poiché l'intero vettore deve essere spostato indietro di uno ogni volta che viene aggiunta una nuova runa .
Questa soluzione funziona sicuramente con i caratteri 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());
}
Una versione che penso funzioni su Unicode. È basato sulle funzioni 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 è un tipo, quindi usalo. Inoltre, Go non utilizza il punto e virgola.
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))
}
prova sotto il codice:
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"))
}
per maggiori informazioni controlla http://golangcookbook.com/chapters/strings/reverse/
e http://www.dotnetperls.com/reverse-string-go
Per stringhe semplici è possibile utilizzare tale costruzione:
func Reverse(str string) string {
if str != "" {
return Reverse(str[1:]) + str[:1]
}
return ""
}
Ecco un'altra soluzione:
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)
}
Tuttavia, la soluzione di yazu sopra è più elegante poiché inverte la []rune
fetta in posizione.
Ancora un'altra soluzione (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, "")
}
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)
}
}
Produzione
Input: GO je úžasné!
Output: !énsažú ej OG
PASS
ok github.com/alesr/reverse-string 0.098s
a+´
invece diá
. Mi chiedo come si possa tenerne conto, senza normalizzarlo.