Jak odwrócić ciąg w Go?

103

Jak możemy odwrócić prosty ciąg w Go?

user211499
źródło
1
O ile rozumiem, poniższe rozwiązania nie działają w przypadku wstępnie skomponowanych lub łączonych postaci, takich jak dawanie a+´zamiast á. Zastanawiam się, jak można to uwzględnić, nie normalizując tego.
siritinga,
Jeśli jesteś zdezorientowany z ogromną liczbą podobnych odpowiedzi, sprawdź mój test porównawczy .
Salvador Dali

Odpowiedzi:

94

W Go1 runa jest typem wbudowanym.

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)
}
yazu
źródło
4
nie możesz użyć len () w Go, aby sprawdzić długość łańcucha / tablicy / plasterka itp ... Oto dlaczego? - len () w Go oznacza rozmiar wejścia w bajtach. Nie odpowiada jego długości. - Nie wszystkie runy utf8 są tego samego rozmiaru. Może to być 1, 2, 4 lub 8. - Powinieneś użyć metody RuneCountInString pakietu Unicode / ut8, aby uzyskać długość runy.
Anvesh Checka
15
@AnveshChecka, to jest niepoprawne. Zobacz golang.org/pkg/builtin/#len - len () na wycinku zdecydowanie zwraca liczbę elementów, a nie rozmiar w bajtach. Kawałek run to właściwy sposób na zrobienie tego.
chowey
3
@ рытфолд To nie działa w przypadku łączenia znaków. Zobacz play.golang.org/p/sBgZAV7gCb , łącząca postać nie jest zamieniana na swoją podstawową.
chowey
53

Sugeruje Russ Cox z listy mailingowej golang-nuts

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)
}
user181548
źródło
20
Podoba mi się, jak zmuszają cię do myślenia o kodowaniu.
György Andrasek
10
off-topic: dlaczego to [golang-nuts] a nie [go-nuts]?
Jimmy
2
Wow, wtf jest z podwójnym przypisaniem podczas cofania? Ciekawy. Teraz pomyśl o sznurku z nierówną liczbą run. Środkowy jest traktowany w specjalny sposób, mimo wszystko z odpowiednim efektem końcowym. :) Interesująca mała optymalizacja, o której nie pomyślałbym od razu.
Kissaki,
4
Nie rozumiem, dlaczego ta konwersja na runę, dlaczego nie rune:=[]rune(input)?
siritinga,
1
Nie potrzebujesz pierwszej pętli dla zakresu. wyjście: = [] rune (wejście); n: = len (wyjście) I nie potrzebujesz runy = runy [0: n]
dvallejo
29

Działa to bez bałaganu z funkcjami:

func Reverse(s string) (result string) {
  for _,v := range s {
    result = string(v) + result
  }
  return 
}
Szymon
źródło
6
Chociaż działa, ponieważ ciągi znaków są niezmienne, jest bardzo nieefektywne. Opublikowałem bardziej wydajne rozwiązanie.
peterSO
5
Jest to o wiele zbyt łatwe do zrozumienia. Spraw, by było trudniej :-) (i „plus jeden” za samo
zajęcie się
2
To najlepsza odpowiedź, chyba że odwrócenie strun jest twoim wąskim gardłem.
Banjocat
1
@dolmen - dlaczego to nie poradzi sobie z łączeniem postaci? zakres na łańcuchu zwraca runę, która jest punktem kodowym.
Stan R.
1
@StanR. Runa to nie glif. Glif może składać się z wielu punktów kodowych / run. Zobacz reedbeta.com/blog/programmers-intro-to-unicode/#combining-marks Odwrócenie punktów kodowych spowoduje dołączenie łączonych znaków do innego podstawowego punktu kodowego.
dolmen
14

Działa to na ciągach Unicode, biorąc pod uwagę dwie rzeczy:

  • zakres działa na łańcuchu, wyliczając znaki Unicode
  • string może być zbudowany z kawałków int, gdzie każdy element jest znakiem Unicode.

Więc oto idzie:

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);
}
Randy Sugianto „Yuku”
źródło
Przypisałbym, i:=len(o)-1a następnie złożyłbym for w jedną linię for _, c:=range s { o[i--]=c; }. Człowieku NIENAWIDZĘ za bez nawiasów - czy to dozwolone:for(_, c:=range s) { o[i--]=c; }
Lawrence Dol
Czy mógłbyś wyjaśnić, co robi _?
Lawrence Dol
6
@Software_Monkey: o [i--] = c nie jest dozwolone w Go. - i ++ to instrukcje, a nie wyrażenia. _ oznacza odrzucenie (zignorowanie) tej zmiennej.
Randy Sugianto „Yuku”
1
z go 1.1+ zwraca błąd w linii string ([] int), jeśli zamiast tego używany jest typ runy [] dla o, wszystko działa
Otuk
1
@yuku: Nadal nie działa s: = "Les Mise \ u0301rables"
Stefan Steiger
13

Z przykładowych projektów Go: golang / example / stringutil / reverse.go , autorstwa Andrew Gerranda

/*
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)
}

Przejdź do placu zabaw, aby odwrócić ciąg

Po odwróceniu łańcucha „bròwn”, poprawnym wynikiem powinno być „nwòrb”, a nie „nẁorb”.
Zwróć uwagę na grób nad literą o.


Aby zachować łączenie znaków Unicode, takich jak „as⃝df̅” z odwrotnym wynikiem „f̅ds⃝a”,
zapoznaj się z innym kodem wymienionym poniżej:

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

Ivan Chau
źródło
2
Dzięki za wyjaśnienie różnicy w stosunku do stackoverflow.com/a/10030772/3093387 - wygląda na to, że te dwa rozwiązania różnią się sposobem, w jaki radzą sobie ze stringami takimi jak „bròwn”.
josliber
Dziękuję za wspomnienie o rozwiązaniu Rosettacode, które obsługuje łączenie znaków
dolmen
11

Zauważyłem to pytanie, kiedy Simon opublikował swoje rozwiązanie które, ponieważ ciągi znaków są niezmienne, jest bardzo nieefektywne. Inne proponowane rozwiązania również są wadliwe; nie działają lub są nieefektywne.

Oto wydajne rozwiązanie, które działa, z wyjątkiem sytuacji, gdy ciąg nie jest prawidłowym kodem UTF-8 lub ciąg zawiera łączone znaki.

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 犬")))
}
peterSO
źródło
1
return string (runy) Działa również.
3
@Tommy: Nie, return string(runes)nie działa we wszystkich przypadkach.
peterSO
czy mógłbyś wyjaśnić trochę więcej, dlaczego tak jest? Zrobiłem krótki program i tam działa, ale może te przypadki, o których mówisz, nie są tam uruchamiane? play.golang.org/p/yk1sAwFjol
1
@Tommy: Twój krótki program po prostu pokazuje, że znak NUL jest NOP, gdy jest wysyłany do drukarki lub terminala. Twoja funkcja Reverse2 nie działa w przypadku ciągów zakodowanych w formacie innym niż ASCII UTF-8. Poprawiłem
peterSO
Jeszcze jedno błędne „rozwiązanie”, które nie obsługuje prawidłowego łączenia znaków.
dolmen
9

Jest tu zbyt wiele odpowiedzi. Niektóre z nich są wyraźnymi duplikatami. Ale nawet z lewej strony trudno wybrać najlepsze rozwiązanie.

Więc przejrzałem odpowiedzi, wyrzuciłem ten, który nie działa dla Unicode, a także usunąłem duplikaty. Porównałem tych, którzy przeżyli, aby znaleźć najszybszego. Tak oto wyniki z przypisania (jeśli zauważy się, że brakowało mi odpowiedzi, ale warto dodać, nie krępuj się zmodyfikować wzorzec):

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

Oto najszybsza metoda rmullera :

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

Z jakiegoś powodu nie mogę dodać testu porównawczego, więc możesz go skopiować z PlayGround(nie możesz tam uruchomić testów). Zmień nazwę i uruchomgo test -bench=.

Salvador Dali
źródło
Żadne z tych „rozwiązań” nie obsługuje poprawnie łączenia znaków .
dolmen
6

Napisałem następującą Reversefunkcję, która uwzględnia kodowanie UTF8 i połączone znaki:

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

Zrobiłem co w mojej mocy, aby był jak najbardziej wydajny i czytelny. Pomysł jest prosty, przejdź przez runy w poszukiwaniu połączonych postaci, a następnie odwróć runy połączonych postaci na miejscu. Gdy już je wszystkie pokryjemy, odwróć na miejscu runy z całego łańcucha.

Powiedzmy, że chcielibyśmy odwrócić ten ciąg bròwn. Symbol òjest reprezentowany przez dwie runy, jedną odla tego unikodu, \u0301aktóry reprezentuje „grób”.

Dla uproszczenia przedstawmy ciąg w ten sposób bro'wn. Pierwszą rzeczą, którą robimy, jest szukanie połączonych znaków i odwracanie ich. Więc teraz mamy ciąg br'own. Na koniec odwracamy cały ciąg i otrzymujemy nwo'rb. To jest zwracane nam jakonwòrb

Możesz go znaleźć tutaj https://github.com/shomali11/util jeśli chcesz go użyć.

Oto kilka przypadków testowych, które pokazują kilka różnych scenariuszy:

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")
}
Raed Shomali
źródło
3

Opierając się na oryginalnej sugestii Stephan202 i wydaje się, że działa dla ciągów znaków 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, "" );
}

Alternatywnie, nie używaj pakietu ciągów, ale nie „bezpieczny dla formatu Unicode”:

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 );
}
Martin Clayton
źródło
+1. To działa. Ale muszę powiedzieć, że to dość dziwne (na razie), że rozdzielanie i łączenie jest konieczne do tak prostego zadania ...
Stephan202
@martin: przepraszam za tę zmianę. Przypadkowo wkleiłem zaktualizowaną odpowiedź w Twoim pytaniu ... bardzo mi wstyd .
Stephan202
@Stephan - nie ma problemu. Dodałem alternatywne rozwiązanie, oparte na funkcji bajtów pakietu ciągów znaków.
Martin Clayton
@Nosradena: Wycofałem się w ciągu tej samej minuty (byłem zaskoczony, widząc, że Martin zaktualizował swoją odpowiedź dokładnie tym samym tekstem, który właśnie napisałem ... i wtedy
dotarło do
@martin: druga wersja wygląda lepiej, jeśli o mnie chodzi :)
Stephan202
3
//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

Używanie strings.Builder jest około 3 razy szybsze niż użycie konkatenacji ciągów

Vlad Bezden
źródło
1
Zastanawiam się, dlaczego to pytanie nie ma pozytywnych głosów, mimo że jest najdokładniejszą odpowiedzią
Nilesh
3

Tutaj jest zupełnie inne, powiedziałbym, bardziej funkcjonalne podejście, nie wymienione wśród innych odpowiedzi:

func reverse(s string) (ret string) {
    for _, v := range s {
        defer func(r rune) { ret += string(r) }(v)
    }
    return
}
Vladimir Bauer
źródło
Jestem prawie pewien, że nie jest to najszybsze rozwiązanie, ale pokazuje, jak zmienna zwracana retjest utrzymywana w stanie zamkniętym do dalszego przetwarzania, przez każdą funkcję odroczenia.
Vladimir Bauer
Powolny i nie obsługuje poprawnie łączenia znaków.
dolmen
1
Nie jestem pewien, jak szybko to jest, ale jest piękne.
donatJ
Wydajność tego można poprawić w Go 1.14. Przynajmniej uwagi do wydania twierdzą, że mają zerowy narzut odroczenia.
Vladimir Bauer
2

To najszybsza realizacja

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)
    }
}
rmuller
źródło
Czy przetestowałeś rozwiązania przed stwierdzeniem, że jest to najszybsza implementacja?
Denys Séguret,
tak zrobiłem, dlatego kod BenchmarkReverse jest obecny :). Jednak nie mam już wyników.
rmuller
Szybkie rozwiązanie, ale nadal błędne, ponieważ nie obsługuje prawidłowego łączenia znaków.
dolmen
Czy to prawda, skoro @dolmen mówi, że to nie radzi sobie z łączeniem postaci? Czy jest tutaj rozwiązanie, które to robi?
geraldss
2

Ten kod zachowuje nienaruszone sekwencje łączonych znaków i powinien działać również z nieprawidłowym wejściem UTF-8.

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

To mogłoby być trochę bardziej wydajne, gdyby prymitywy Unicode / norm pozwalały na iterację przez granice łańcucha bez przydzielania. Zobacz też https://code.google.com/p/go/issues/detail?id=9055 .

rog
źródło
Nie ma takiego „nieprawidłowego wejścia UTF-8” w wartościach łańcuchowych: podczas konwersji z []bytena stringGo zastępuje „nieprawidłowe dane wejściowe UTF-8” prawidłowym punktem kodowym \uFFFD.
dolmen
Nie rozumiem powyższego komentarza. Czy twierdzisz, że zachowanie tego kodu jest nieprawidłowe, gdy jest przedstawiany z ciągiem zawierającym nieprawidłowy kod UTF-8?
rog
Nie. Mówię, że nieprawidłowy UTF-8 w Go stringnie istnieje. Ale może istnieć w []byte.
dolmen
Ciąg znaków Go może zawierać dokładnie tyle nieprawidłowego utf-8, co bajt []. Na przykład: play.golang.org/p/PG0I4FJfEN
rog
2

Jeśli potrzebujesz obsługiwać klastry grafemów, użyj modułu unicode lub 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
}
masakielastic
źródło
Chciałbym dać ci 1000 głosów za. Wszystkie inne implementacje na tej stronie nieprawidłowo odwracają ŁAŃCUCH (ŁAŃCUCH NIE jest sekwencją znaków).
Stefan Steiger,
To nie działa. Jeśli dwukrotnie odwrócisz ciąg, nie otrzymasz oryginalnego ciągu. Początkowy łącznik Diaeresis (\ u0308), użyty w tym przykładzie, łączy się z poprzedzającymi znakami, tworząc podwójny umlaut „a” po odwróceniu. Jeśli strwyjście jest cytowane, modyfikuje początkowy cudzysłów!
Joshua Kolden
2

Możesz również zaimportować istniejącą implementację:

import "4d63.com/strrev"

Następnie:

strrev.Reverse("abåd") // returns "dåba"

Lub odwrócić ciąg zawierający znaki łączące unicode:

strrev.ReverseCombining("abc\u0301\u031dd") // returns "d\u0301\u031dcba"

Te implementacje obsługują poprawną kolejność wielobajtów Unicode i łączenie znaków po odwróceniu.

Uwaga: Wbudowane funkcje odwracania ciągów znaków w wielu językach programowania nie zachowują łączenia, a identyfikacja łączonych znaków wymaga znacznie więcej czasu na wykonanie.

Leigh McCulloch
źródło
1

Z pewnością nie jest to najbardziej wydajne rozwiązanie pod względem wykorzystania pamięci, ale w przypadku „prostego” bezpiecznego rozwiązania UTF-8 następujące elementy wykonają zadanie i nie zepsują run.

Moim zdaniem najbardziej czytelny i zrozumiały na stronie.

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

    return
}
donatJ
źródło
1

Poniższe dwie metody działają szybciej niż najszybsze rozwiązanie, które zachowuje łączenie znaków , chociaż nie oznacza to, że brakuje mi czegoś w mojej konfiguracji testu porównawczego.

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

Druga metoda zainspirowana tym

//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
Sridhar
źródło
Oto, czego brakuje w Twoim benchmarku: Twoje rozwiązanie jest szybsze, ponieważ nie zachowuje łączenia znaków. Porównywanie ich jest po prostu niesprawiedliwe.
dolmen
1

UWAGA: Ta odpowiedź pochodzi z 2009 roku, więc prawdopodobnie istnieją już lepsze rozwiązania.


Wygląda trochę „okrężnie” i prawdopodobnie niezbyt wydajnie, ale ilustruje, w jaki sposób interfejs Reader może być używany do odczytu z ciągów. IntVectors również wydają się bardzo przydatne jako bufory podczas pracy z łańcuchami utf8.

Byłby jeszcze krótszy w przypadku pominięcia części `` rozmiaru '' i wstawienia do wektora przez Insert, ale myślę, że byłoby to mniej wydajne, ponieważ cały wektor musi być następnie cofany o jeden za każdym razem, gdy dodawana jest nowa runa .

To rozwiązanie zdecydowanie działa ze znakami 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());
}
Oliver Mason
źródło
Dlaczego dodajesz te wszystkie końcowe średniki?
Morteza R
@ olivier-mason Czas nauczyć się gofmt podczas udostępniania kodu Go.
dolmen
1
Ta odpowiedź pochodziła sprzed ośmiu lat.
Oliver Mason
@OliverMason Nigdy nie jest za późno, aby naprawić (lub usunąć) niedoskonałe rozwiązanie.
dolmen
0

Wersja, która moim zdaniem działa na Unicode. Jest zbudowany na funkcjach 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);
}
Jonathan Wright
źródło
0

runa to typ, więc używaj jej. Ponadto Go nie używa średników.

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))
}
Walter
źródło
Kiedy zadawano to pytanie, używano średników.
OneOfOne
Jeszcze jedno błędne „rozwiązanie”, które nie obsługuje prawidłowego łączenia znaków.
dolmen
0

Do prostych sznurków można zastosować taką konstrukcję:

func Reverse(str string) string {
    if str != "" {
        return Reverse(str[1:]) + str[:1]
    }
    return ""   
}
Sergo Kurbanov
źródło
-1

Oto jeszcze jedno rozwiązanie:

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

Jednak powyższe rozwiązanie yazu jest bardziej eleganckie, ponieważ odwraca []runeplasterek w miejscu.

Jabba
źródło
-1

Jeszcze inne rozwiązanie (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)
}
OneOfOne
źródło
-1
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)
    }
}

Wynik

Input: GO je úžasné!
Output: nsažú ej OG
PASS
ok      github.com/alesr/reverse-string 0.098s
Alessandro Resta
źródło
Działa, jeśli wejście jest w NFC. Ale jak większość innych złych rozwiązań tutaj, nie działa z łączeniem postaci.
dolmen
-1
    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
    }
saurabh
źródło