Pelo que entendi, as soluções fornecidas a seguir não funcionam com caracteres pré-compostos ou combinados, como dar em a+´vez de á. Eu me pergunto como isso poderia ser levado em consideração, sem normalizá-lo.
siritinga
Se você está confuso com um grande número de respostas semelhantes, verifique meu benchmark .
Salvador Dali
Respostas:
94
Em Go1, a runa é um tipo embutido.
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]}returnstring(runes)}
você não pode usar len () em Go para descobrir o comprimento de uma string / Array / Slice etc ... Por quê? - len () em Go significa o tamanho da entrada em bytes. Não corresponde ao seu comprimento. - Nem todas as runas do utf8 são do mesmo tamanho. Pode ser 1, 2, 4 ou 8. - Você deve usar o método RuneCountInString do pacote unicode / ut8 para obter o comprimento da runa.
Anvesh Checka
15
@AnveshChecka, isso está incorreto. Veja golang.org/pkg/builtin/#len - len () em uma fatia definitivamente retorna o número de elementos, não o tamanho em bytes. Uma fatia de runas é a maneira correta de fazer isso.
chowey de
3
@ рытфолд Isso não funciona com a combinação de caracteres. Consulte play.golang.org/p/sBgZAV7gCb , o caractere de combinação não é trocado por sua base.
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)}
Eu gosto de como eles o forçam a pensar sobre codificações.
György Andrasek
10
fora do tópico: por que é [nozes golang] e não [nozes]?
Jimmy,
2
Uau, qual é a dupla atribuição ao reverter? Interessante. Agora, pense em uma corda com um número ímpar de runas. O do meio recebe tratamento especial, com o resultado final correto, no entanto. :) Uma pequena otimização interessante que eu não teria pensado de imediato.
Kissaki
4
Não entendo por que essa conversão para runa, por que não rune:=[]rune(input)?
siritinga
1
Você não precisa do primeiro para o loop de alcance. saída: = [] runa (entrada); n: = len (saída) E você não precisa da runa = runa [0: n]
dvallejo
29
Isso funciona, sem toda a confusão com as funções:
func Reverse(s string)(result string){for _,v := range s {
result =string(v)+ result
}return}
Eu atribuiria i:=len(o)-1e dobraria o for em uma única linha for _, c:=range s { o[i--]=c; }. Cara, eu ODEIO o sem parênteses - isso é permitido:for(_, c:=range s) { o[i--]=c; }
Lawrence Dol
Você poderia explicar o que _ faz?
Lawrence Dol de
6
@Software_Monkey: o [i--] = c não é permitido no Go. - e ++ são declarações, não expressões. _ significa descartar (ignorar) essa variável.
Randy Sugianto 'Yuku'
1
com go 1.1+ ele retorna um erro na linha string ([] int), se em vez disso [] tipo de runa for usado para o, tudo funciona
Otuk
1
@yuku: Ainda falha em s: = "Les Mise \ u0301rables"
/*
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]}returnstring(r)}
Obrigado por esclarecer a diferença de stackoverflow.com/a/10030772/3093387 - parece que essas duas soluções diferem na forma como lidam com strings como "bròwn".
josliber
Obrigado por mencionar a solução Rosettacode que lida com a combinação de caracteres
dolmen
11
Percebi essa pergunta quando Simon postou sua solução que, como as strings são imutáveis, é muito ineficiente. As outras soluções propostas também são falhas; eles não funcionam ou são ineficientes.
Esta é uma solução eficiente que funciona, exceto quando a string não é UTF-8 válida ou a string contém caracteres combinados.
package main
import"fmt"
func Reverse(s string)string{
n := len(s)
runes := make([]rune, n)for _, rune := range s {
n--
runes[n]= rune
}returnstring(runes[n:])}
func main(){
fmt.Println(Reverse(Reverse("Hello, 世界")))
fmt.Println(Reverse(Reverse("The quick brown 狐 jumped over the lazy 犬")))}
@Tommy: Não, return string(runes)não funciona para todos os casos.
peterSO
você poderia explicar um pouco mais sobre o porquê disso? Fiz um programa curto e funciona lá, mas talvez os casos de que você fala não sejam acionados aí? play.golang.org/p/yk1sAwFjol
1
@Tommy: Seu programa curto meramente demonstra que o caractere NUL é um NOP quando enviado a uma impressora ou terminal. A função Reverse2 falha para strings codificadas não ASCII UTF-8. Revisei
peterSO
Mais uma "solução" errada que não lida com a combinação de caracteres corretamente.
Dolmen
9
Existem muitas respostas aqui. Alguns deles são duplicatas claras. Mas, mesmo da esquerda, é difícil selecionar a melhor solução.
Então eu fui pelas respostas, joguei fora a que não funciona para Unicode e também removi as duplicatas. Eu comparei os sobreviventes para encontrar o mais rápido. Então, aqui estão os resultados com atribuição (se você notar as respostas que perdi, mas vale a pena adicionar, sinta-se à vontade para modificar o benchmark):
Por alguma razão, não consigo adicionar um benchmark, então você pode copiá-lo PlayGround(você não pode executar testes lá). Renomeie-o e executego test -bench=.
Escrevi a seguinte Reversefunção que respeita a codificação UTF8 e os caracteres combinados:
// 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,0for i < textRunesLength && j < textRunesLength {
j = i +1for 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)returnstring(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)}
Fiz o meu melhor para torná-lo o mais eficiente e legível possível. A ideia é simples, atravesse as runas procurando por caracteres combinados e então inverta as runas dos personagens combinados no local. Depois de cobrir todos eles, inverta as runas de toda a corda no lugar.
Digamos que gostaríamos de reverter essa string bròwn. O òé representado por duas runas, uma para o oe outra para este unicode \u0301aque representa o "túmulo".
Para simplificar, vamos representar a string desta forma bro'wn. A primeira coisa que fazemos é procurar caracteres combinados e invertê-los. Portanto, agora temos a corda br'own. Finalmente, invertemos toda a string e terminamos com nwo'rb. Isso é devolvido a nós comonwòrb
+1. Isso funciona. Mas devo dizer que é um tanto estranho (por enquanto) que a divisão e a junção sejam necessárias para uma tarefa tão simples ...
Stephan202
@martin: desculpe pela edição. Eu colei acidentalmente minha resposta atualizada em sua pergunta ... estou com muita vergonha .
Stephan202
@Stephan - sem problema. Eu adicionei uma solução alternativa, com base na função Bytes do pacote de strings.
Martin Clayton
@Nosradena: Voltei no mesmo minuto (fiquei surpreso ao ver que Martin atualizou sua resposta com exatamente o mesmo texto que eu tinha acabado de escrever ... e então me ocorreu;)
Stephan202
@martin: a segunda versão fica melhor se você me perguntar :)
Stephan202
3
//Reverse reverses string using strings.Builder. It's about 3 times faster//than the one with using a string concatenation
func Reverse(instring)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(instring)(outstring){for _, r := range in{out=string(r)+out}return}BenchmarkReverseStringConcatenation-810000001571 ns/op 176 B/op 29 allocs/op
BenchmarkReverseStringsBuilder-83000000499 ns/op 56 B/op 6 allocs/op
Usar strings.Builder é cerca de 3 vezes mais rápido do que usar concatenação de string
Tenho certeza de que não é a solução mais rápida, mas mostra como a variável de retorno reté mantida em fechamento para processamento posterior, por cada função defer.
Vladimir Bauer
Lento e não lida com a combinação de caracteres corretamente.
Dolmen
1
Não tenho certeza de quão rápido isso é, mas é lindo.
donatJ
O desempenho deste pode ser melhorado no Go 1.14. Pelo menos as notas de versão afirmam ter zero overhead de adiamento.
Vladimir Bauer
2
Esta é a implementação mais rápida
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)}returnstring(buf)}const(
s ="The quick brown 狐 jumped over the lazy 犬"
reverse ="犬 yzal eht revo depmuj 狐 nworb kciuq ehT")
func TestReverse(t *testing.T){ifReverse(s)!= reverse {
t.Error(s)}}
func BenchmarkReverse(b *testing.B){for i :=0; i < b.N; i++{Reverse(s)}}
Poderia ser um pouco mais eficiente se as primitivas unicode / norm permitissem a iteração pelos limites de uma string sem alocação. Consulte também https://code.google.com/p/go/issues/detail?id=9055 .
Não existe tal "entrada UTF-8 inválida" em valores de string: ao converter de []bytepara stringGo substitui "entrada UTF-8 inválida" por um ponto de código válido \uFFFD.
Dolmen de
Eu não entendo o comentário acima. Você está dizendo que o comportamento desse código está errado quando apresentado com uma string contendo UTF-8 inválido?
rog
Não. Estou dizendo que o UTF-8 inválido em um Go stringnão existe. Mas pode existir em um []byte.
dolmen
Uma string Go pode conter exatamente tanto utf-8 inválido quanto um byte []. Por exemplo: play.golang.org/p/PG0I4FJfEN
rog
2
Se você precisar lidar com clusters de grafemas, use o módulo 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)ifchecked==false{checked=true}}elseifchecked==false{
ret =string(append([]rune(""), c))+ ret
}else{
buf = append(buf, c)}
index +=1}returnstring(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
}
Eu gostaria de dar a você 1.000 votos positivos. Todas as outras implementações nesta página invertem um STRING incorretamente (um STRING NÃO é uma sequência de caracteres).
Stefan Steiger
Isso não funciona. Se você inverter a string, não obterá a string original. O Diaeresis Combinante principal (\ u0308), usado neste exemplo, combina-se com os caracteres precedentes, criando um trema duplo 'a' quando invertido. Se a strsaída for citada, ela modifica a citação inicial!
Joshua Kolden
2
Você também pode importar uma implementação existente:
import"4d63.com/strrev"
Então:
strrev.Reverse("abåd")// returns "dåba"
Ou para inverter uma string incluindo caracteres de combinação Unicode:
Essas implementações suportam a ordenação correta de caracteres multibyte Unicode e combing quando invertidos.
Nota: As funções reversas de string integradas em muitas linguagens de programação não preservam a combinação, e a identificação de caracteres combinados requer muito mais tempo de execução.
Certamente não é a solução mais eficiente em termos de memória, mas para uma solução segura UTF-8 "simples", o seguinte fará o trabalho e não quebrará runas.
Na minha opinião, é o mais legível e compreensível da página.
func reverseStr(str string)(outstring){for _, s := range str {out=string(s)+out}return}
Os dois métodos a seguir são executados mais rapidamente do que a solução mais rápida que preserva a combinação de caracteres , embora isso não queira dizer que esteja faltando algo em minha configuração de benchmark.
Aqui está o que está faltando em seu benchmark: sua solução é mais rápida porque não preserva a combinação de caracteres. É simplesmente injusto compará-los.
Dolmen de
1
NOTA: Esta resposta é de 2009, então provavelmente existem soluções melhores por aí agora.
Parece um pouco "indireto" e provavelmente não é muito eficiente, mas ilustra como a interface do Reader pode ser usada para ler strings. IntVectors também parecem muito adequados como buffers ao trabalhar com strings utf8.
Seria ainda mais curto deixando de fora a parte do 'tamanho' e a inserção no vetor por Insert, mas acho que seria menos eficiente, pois o vetor inteiro precisa ser empurrado para trás em um cada vez que uma nova runa é adicionada .
Esta solução definitivamente funciona com caracteres 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);}returnstring(output.Data());}
runa é um tipo, então use-a. Além disso, Go não usa ponto-e-vírgula.
func reverse(s string)string{
l := len(s)
m := make([]rune, l)for _, c := range s {
l--
m[l]= c
}returnstring(m)}
func main(){
str :="the quick brown 狐 jumped over the lazy 犬"
fmt.Printf("reverse(%s): [%s]\n", str, reverse(str))}
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 stringsfor 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{returnstring(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 stringif strLen ==0{return s
}// Same aboveif 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,"")}
Teste
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)}}
Resultado
Input: GO je úžasné!Output:!énsažú ej OG
PASS
ok github.com/alesr/reverse-string0.098s
a+´
vez deá
. Eu me pergunto como isso poderia ser levado em consideração, sem normalizá-lo.Respostas:
Em Go1, a runa é um tipo embutido.
fonte
Russ Cox, na lista de discussão golang-nuts , sugere
fonte
rune:=[]rune(input)
?Isso funciona, sem toda a confusão com as funções:
fonte
Isso funciona em strings Unicode considerando 2 coisas:
Então aqui vai:
fonte
i:=len(o)-1
e dobraria o for em uma única linhafor _, c:=range s { o[i--]=c; }
. Cara, eu ODEIO o sem parênteses - isso é permitido:for(_, c:=range s) { o[i--]=c; }
De projetos de exemplo Go: golang / example / stringutil / reverse.go , de Andrew Gerrand
Vá ao Playground para inverter uma corda
Depois de inverter a string "bròwn", o resultado correto deve ser "nwòrb", não "nẁorb".
Observe a sepultura acima da letra o.
Para preservar caracteres de combinação Unicode como "as⃝df̅" com o resultado reverso "f̅ds⃝a",
consulte outro código listado abaixo:
http://rosettacode.org/wiki/Reverse_a_string#Go
fonte
Percebi essa pergunta quando Simon postou sua solução que, como as strings são imutáveis, é muito ineficiente. As outras soluções propostas também são falhas; eles não funcionam ou são ineficientes.
Esta é uma solução eficiente que funciona, exceto quando a string não é UTF-8 válida ou a string contém caracteres combinados.
fonte
return string(runes)
não funciona para todos os casos.Existem muitas respostas aqui. Alguns deles são duplicatas claras. Mas, mesmo da esquerda, é difícil selecionar a melhor solução.
Então eu fui pelas respostas, joguei fora a que não funciona para Unicode e também removi as duplicatas. Eu comparei os sobreviventes para encontrar o mais rápido. Então, aqui estão os resultados com atribuição (se você notar as respostas que perdi, mas vale a pena adicionar, sinta-se à vontade para modificar o benchmark):
Então, aqui está o método mais rápido de rmuller :
Por alguma razão, não consigo adicionar um benchmark, então você pode copiá-lo PlayGround(você não pode executar testes lá). Renomeie-o e execute
go test -bench=.
fonte
Escrevi a seguinte
Reverse
função que respeita a codificação UTF8 e os caracteres combinados:Fiz o meu melhor para torná-lo o mais eficiente e legível possível. A ideia é simples, atravesse as runas procurando por caracteres combinados e então inverta as runas dos personagens combinados no local. Depois de cobrir todos eles, inverta as runas de toda a corda no lugar.
Digamos que gostaríamos de reverter essa string
bròwn
. Oò
é representado por duas runas, uma para oo
e outra para este unicode\u0301a
que representa o "túmulo".Para simplificar, vamos representar a string desta forma
bro'wn
. A primeira coisa que fazemos é procurar caracteres combinados e invertê-los. Portanto, agora temos a cordabr'own
. Finalmente, invertemos toda a string e terminamos comnwo'rb
. Isso é devolvido a nós comonwòrb
Você pode encontrá-lo aqui https://github.com/shomali11/util se desejar usá-lo.
Aqui estão alguns casos de teste para mostrar alguns cenários diferentes:
fonte
Com base na sugestão original de Stephan202 e parece funcionar para strings Unicode:
Alternativo, não usando o pacote de strings, mas não 'seguro para Unicode':
fonte
Usar strings.Builder é cerca de 3 vezes mais rápido do que usar concatenação de string
fonte
Aqui é bem diferente, eu diria uma abordagem mais funcional, não listada entre outras respostas:
fonte
ret
é mantida em fechamento para processamento posterior, por cada função defer.Esta é a implementação mais rápida
fonte
Este código preserva as sequências de caracteres combinados intactas e também deve funcionar com entrada UTF-8 inválida.
Poderia ser um pouco mais eficiente se as primitivas unicode / norm permitissem a iteração pelos limites de uma string sem alocação. Consulte também https://code.google.com/p/go/issues/detail?id=9055 .
fonte
[]byte
parastring
Go substitui "entrada UTF-8 inválida" por um ponto de código válido\uFFFD
.string
não existe. Mas pode existir em um[]byte
.Se você precisar lidar com clusters de grafemas, use o módulo Unicode ou regexp.
fonte
str
saída for citada, ela modifica a citação inicial!Você também pode importar uma implementação existente:
Então:
Ou para inverter uma string incluindo caracteres de combinação Unicode:
Essas implementações suportam a ordenação correta de caracteres multibyte Unicode e combing quando invertidos.
Nota: As funções reversas de string integradas em muitas linguagens de programação não preservam a combinação, e a identificação de caracteres combinados requer muito mais tempo de execução.
fonte
Certamente não é a solução mais eficiente em termos de memória, mas para uma solução segura UTF-8 "simples", o seguinte fará o trabalho e não quebrará runas.
Na minha opinião, é o mais legível e compreensível da página.
fonte
Os dois métodos a seguir são executados mais rapidamente do que a solução mais rápida que preserva a combinação de caracteres , embora isso não queira dizer que esteja faltando algo em minha configuração de benchmark.
Segundo método inspirado neste
fonte
NOTA: Esta resposta é de 2009, então provavelmente existem soluções melhores por aí agora.
Parece um pouco "indireto" e provavelmente não é muito eficiente, mas ilustra como a interface do Reader pode ser usada para ler strings. IntVectors também parecem muito adequados como buffers ao trabalhar com strings utf8.
Seria ainda mais curto deixando de fora a parte do 'tamanho' e a inserção no vetor por Insert, mas acho que seria menos eficiente, pois o vetor inteiro precisa ser empurrado para trás em um cada vez que uma nova runa é adicionada .
Esta solução definitivamente funciona com caracteres utf8.
fonte
Uma versão que acho que funciona em Unicode. Ele é baseado nas funções utf8.Rune:
fonte
runa é um tipo, então use-a. Além disso, Go não usa ponto-e-vírgula.
fonte
tente o código abaixo:
para obter mais informações, verifique http://golangcookbook.com/chapters/strings/reverse/
e http://www.dotnetperls.com/reverse-string-go
fonte
Para strings simples, é possível usar essa construção:
fonte
Aqui está outra solução:
No entanto, a solução de yazu acima é mais elegante, pois ele inverte a
[]rune
fatia no lugar.fonte
Ainda outra solução (tm):
fonte
Teste
Resultado
fonte
fonte