Por lo que tengo entendido, las soluciones que se dan a continuación no funcionan con caracteres precompuestos o combinados, como dar en a+´lugar de á. Me pregunto cómo se podría tener eso en cuenta, sin normalizarlo.
no puede usar len () en Go para averiguar la longitud de una cadena / Array / Slice, etc. ¿Por qué? - len () en Go significa el tamaño de la entrada en bytes. No corresponde a su longitud. - No todas las runas de utf8 son del mismo tamaño. Puede ser 1, 2, 4 u 8. - Debe usar el método del paquete unicode / ut8 RuneCountInString para obtener la longitud de la runa.
Anvesh Checka
15
@AnveshChecka, eso es incorrecto. Consulte golang.org/pkg/builtin/#len - len () en un segmento definitivamente devuelve el número de elementos, no el tamaño en bytes. Un trozo de runas es la forma correcta de hacerlo.
chowey
3
@ рытфолд Esto no funciona con la combinación de caracteres. Consulte play.golang.org/p/sBgZAV7gCb , el carácter de combinación no se intercambia con su 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)}
Me gusta cómo te obligan a pensar en codificaciones.
György Andrasek
10
fuera del tema: ¿por qué es [golang-nuts] y no [go-nuts]?
Jimmy
2
Vaya, ¿qué pasa con la doble asignación al dar marcha atrás? Interesante. Ahora, piense en una cuerda con un número impar de runas. El del medio recibe un tratamiento especial, con el resultado final correcto después de todo. :) Una pequeña optimización interesante en la que no habría pensado de inmediato.
Kissaki
4
No entiendo por qué esta conversión a runa, ¿por qué no rune:=[]rune(input)?
siritinga
1
No necesitas el primero para el bucle de rango. salida: = [] runa (entrada); n: = len (salida) Y no necesitas la runa = runa [0: n]
dvallejo
29
Esto funciona, sin todos los problemas con las funciones:
func Reverse(s string)(result string){for _,v := range s {
result =string(v)+ result}return}
Asignaría i:=len(o)-1y luego doblaría el for en una sola línea for _, c:=range s { o[i--]=c; }. Hombre, ODIO el por sin paréntesis - ¿está permitido?for(_, c:=range s) { o[i--]=c; }
Lawrence Dol
¿Podrías explicar qué hace _?
Lawrence Dol
6
@Software_Monkey: o [i--] = c no está permitido en Go. - y ++ son declaraciones, no expresiones. _ significa descartar (ignorar) esa variable.
Randy Sugianto 'Yuku'
1
con go 1.1+ devuelve un error en la línea de cadena ([] int), si en su lugar se usa el tipo de runa [] para o, todo funciona
/*
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)}
Gracias por aclarar la diferencia con stackoverflow.com/a/10030772/3093387 - parece que estas dos soluciones difieren en cómo manejan cadenas como "bròwn".
josliber
Gracias por mencionar la solución Rosettacode que maneja la combinación de caracteres
dolmen
11
Noté esta pregunta cuando Simon publicó su solución que, dado que las cadenas son inmutables, es muy ineficiente. Las otras soluciones propuestas también son defectuosas; no funcionan o son ineficientes.
Esta es una solución eficiente que funciona, excepto cuando la cadena no es UTF-8 válida o la cadena contiene caracteres combinados.
package mainimport"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: No, return string(runes)no funciona en todos los casos.
peterSO
¿Podría explicar un poco más por qué es así? Hice un programa corto y funciona ahí, pero ¿quizás esos casos de los que hablas no se activan ahí? play.golang.org/p/yk1sAwFjol
1
@Tommy: Su programa corto simplemente demuestra que el carácter NUL es un NOP cuando se envía a una impresora o terminal. Su función Reverse2 falla para cadenas codificadas no ASCII UTF-8. Revisé su programa corto para que sea una prueba válida: play.golang.org/p/Ic5G5QEO93
peterSO
Otra "solución" incorrecta que no maneja la combinación de caracteres correctamente.
dolmen
9
Aquí hay demasiadas respuestas. Algunos de ellos son claros duplicados. Pero incluso desde la izquierda, es difícil seleccionar la mejor solución.
Así que revisé las respuestas, tiré la que no funciona para Unicode y también eliminé los duplicados. Evalué a los supervivientes para encontrar el más rápido. Entonces, aquí están los resultados con atribución (si nota las respuestas que me perdí, pero que vale la pena agregar, no dude en modificar el punto de referencia):
Por alguna razón, no puedo agregar un punto de referencia, por lo que puede copiarlo PlayGround(no puede ejecutar pruebas allí). Cambiar el nombre y ejecutargo test -bench=.
Escribí la siguiente Reversefunción que respeta la codificación UTF8 y los 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)}
Hice todo lo posible para que fuera lo más eficiente y legible posible. La idea es simple, atraviesa las runas en busca de personajes combinados y luego invierte las runas de los personajes combinados en su lugar. Una vez que los hayamos cubierto todos, invierta las runas de toda la cuerda también en su lugar.
Digamos que nos gustaría invertir esta cadena bròwn. El òestá representado por dos runas, una para el oy otra para este unicode \u0301aque representa la "tumba".
Para simplificar, representemos la cadena de esta manera bro'wn. Lo primero que hacemos es buscar caracteres combinados y revertirlos. Entonces ahora tenemos la cadena br'own. Finalmente, invertimos toda la cadena y terminamos con nwo'rb. Esto se nos devuelve comonwòrb
+1. Eso funciona. Pero debo decir que es bastante extraño (por ahora) que dividir y unir sea necesario para una tarea tan simple ...
Stephan202
@martin: perdón por esa edición. Accidentalmente pegué mi respuesta actualizada en su pregunta ... me avergüenza mucho .
Stephan202
@ Stephan, no hay problema. Agregué una solución alternativa, basada en la función Bytes del paquete de cadenas.
Martin Clayton
@Nosradena: retrocedí en el mismo minuto (me sorprendió ver que Martin actualizó su respuesta con exactamente el mismo texto que acababa de escribir ... y luego me
di
@martin: la segunda versión se ve mejor si me preguntas :)
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 es aproximadamente 3 veces más rápido que usar la concatenación de cadenas
Estoy bastante seguro de que no es la solución más rápida, pero muestra cómo la variable de retorno retse mantiene cerrada para su procesamiento posterior, por cada función de aplazamiento.
Vladimir Bauer
Lento y no maneja la combinación de personajes correctamente.
dolmen
1
No estoy seguro de qué tan rápido es eso, pero es hermoso.
donatJ
El rendimiento de este se puede mejorar en Go 1.14. Al menos las notas de la versión afirman tener cero gastos generales de aplazamiento.
Vladimir Bauer
2
Esta es la implementación más 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)}}
Podría ser un poco más eficiente si las primitivas unicode / norm permitieran iterar a través de los límites de una cadena sin asignar. Consulte también https://code.google.com/p/go/issues/detail?id=9055 .
No existe tal "entrada UTF-8 no válida" en los valores de cadena: al convertir de []bytea stringGo, se reemplaza la "entrada UTF-8 no válida" por un punto de código válido \uFFFD.
dolmen
No entiendo el comentario anterior. ¿Está diciendo que el comportamiento de este código es incorrecto cuando se presenta con una cadena que contiene UTF-8 no válido?
rog
No. Estoy diciendo que UTF-8 inválido en un Go stringno existe. Pero puede existir en a []byte.
dolmen
Una cadena Go puede contener exactamente tanto utf-8 no válido como un byte []. Por ejemplo: play.golang.org/p/PG0I4FJfEN
rog
2
Si necesita manejar grupos de grafemas, use el módulo 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)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
}
Me gustaría darte 1000 votos a favor. Todas las demás implementaciones de esta página invierten una STRING de forma incorrecta (una STRING NO es una secuencia de caracteres).
Stefan Steiger
Esto no funciona. Si invierte dos veces la cadena, no obtiene la cadena original. La diéresis combinada inicial (\ u0308), utilizada en este ejemplo, se combina con los caracteres precedentes creando una diéresis doble 'a' cuando se invierte. Si strse cotiza la salida, modifica la cotización inicial.
Joshua Kolden
2
También puede importar una implementación existente:
import"4d63.com/strrev"
Luego:
strrev.Reverse("abåd")// returns "dåba"
O para invertir una cadena que incluya caracteres de combinación Unicode:
Estas implementaciones admiten el orden correcto de unicode multibyte y la combinación de caracteres cuando se invierte.
Nota: Las funciones de inversión de cadena incorporadas en muchos lenguajes de programación no conservan la combinación, y la identificación de caracteres combinados requiere mucho más tiempo de ejecución.
Seguramente no es la solución más eficiente en memoria, pero para una solución segura UTF-8 "simple", lo siguiente hará el trabajo y no romperá las runas.
En mi opinión, es el más legible y comprensible de la página.
func reverseStr(str string)(outstring){for _, s := range str {out=string(s)+out}return}
Los siguientes dos métodos se ejecutan más rápido que la solución más rápida que conserva la combinación de caracteres , aunque eso no quiere decir que me esté perdiendo algo en mi configuración de referencia.
Esto es lo que falta en su punto de referencia: su solución es más rápida porque no conserva la combinación de caracteres. Es injusto compararlos.
dolmen
1
NOTA: Esta respuesta es de 2009, por lo que probablemente ya existen mejores soluciones.
Parece un poco "indirecto" y probablemente no muy eficiente, pero ilustra cómo se puede usar la interfaz de Reader para leer cadenas. Los IntVectors también parecen muy adecuados como búfer cuando se trabaja con cadenas utf8.
Sería aún más corto si se omite la parte de 'tamaño' y la inserción en el vector mediante Insertar, pero supongo que sería menos eficiente, ya que todo el vector debe retroceder uno cada vez que se agrega una nueva runa. .
Esta solución definitivamente funciona con 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 es un tipo, así que úsala. Además, Go no usa punto y coma.
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,"")}
Prueba
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)}}
Salida
Input: GO je úžasné!Output:!énsažú ej OG
PASS
ok github.com/alesr/reverse-string0.098s
a+´
lugar deá
. Me pregunto cómo se podría tener eso en cuenta, sin normalizarlo.Respuestas:
En Go1, la runa es un tipo incorporado.
fuente
Russ Cox, en la lista de correo de golang-nuts , sugiere
fuente
rune:=[]rune(input)
?Esto funciona, sin todos los problemas con las funciones:
fuente
Esto funciona en cadenas Unicode considerando 2 cosas:
Así que aquí va:
fuente
i:=len(o)-1
y luego doblaría el for en una sola líneafor _, c:=range s { o[i--]=c; }
. Hombre, ODIO el por sin paréntesis - ¿está permitido?for(_, c:=range s) { o[i--]=c; }
De proyectos de ejemplo de Go: golang / example / stringutil / reverse.go , por Andrew Gerrand
Go Playground para revertir una cuerda
Después de invertir la cadena "bròwn", el resultado correcto debería ser "nwòrb", no "nẁorb".
Tenga en cuenta la tumba sobre la letra o.
Para conservar caracteres de combinación Unicode como "as⃝df̅" con el resultado inverso "f̅ds⃝a",
consulte otro código que se enumera a continuación:
http://rosettacode.org/wiki/Reverse_a_string#Go
fuente
Noté esta pregunta cuando Simon publicó su solución que, dado que las cadenas son inmutables, es muy ineficiente. Las otras soluciones propuestas también son defectuosas; no funcionan o son ineficientes.
Esta es una solución eficiente que funciona, excepto cuando la cadena no es UTF-8 válida o la cadena contiene caracteres combinados.
fuente
return string(runes)
no funciona en todos los casos.Aquí hay demasiadas respuestas. Algunos de ellos son claros duplicados. Pero incluso desde la izquierda, es difícil seleccionar la mejor solución.
Así que revisé las respuestas, tiré la que no funciona para Unicode y también eliminé los duplicados. Evalué a los supervivientes para encontrar el más rápido. Entonces, aquí están los resultados con atribución (si nota las respuestas que me perdí, pero que vale la pena agregar, no dude en modificar el punto de referencia):
Así que aquí está el método más rápido de rmuller :
Por alguna razón, no puedo agregar un punto de referencia, por lo que puede copiarlo PlayGround(no puede ejecutar pruebas allí). Cambiar el nombre y ejecutar
go test -bench=.
fuente
Escribí la siguiente
Reverse
función que respeta la codificación UTF8 y los caracteres combinados:Hice todo lo posible para que fuera lo más eficiente y legible posible. La idea es simple, atraviesa las runas en busca de personajes combinados y luego invierte las runas de los personajes combinados en su lugar. Una vez que los hayamos cubierto todos, invierta las runas de toda la cuerda también en su lugar.
Digamos que nos gustaría invertir esta cadena
bròwn
. Elò
está representado por dos runas, una para elo
y otra para este unicode\u0301a
que representa la "tumba".Para simplificar, representemos la cadena de esta manera
bro'wn
. Lo primero que hacemos es buscar caracteres combinados y revertirlos. Entonces ahora tenemos la cadenabr'own
. Finalmente, invertimos toda la cadena y terminamos connwo'rb
. Esto se nos devuelve comonwòrb
Puede encontrarlo aquí https://github.com/shomali11/util si desea utilizarlo.
A continuación, se muestran algunos casos de prueba para mostrar un par de escenarios diferentes:
fuente
Se basa en la sugerencia original de Stephan202 y parece funcionar para cadenas Unicode:
Alternativo, sin usar el paquete de cadenas, pero no 'seguro para Unicode':
fuente
Usar strings.Builder es aproximadamente 3 veces más rápido que usar la concatenación de cadenas
fuente
Aquí es bastante diferente, diría que un enfoque más funcional, que no figura entre otras respuestas:
fuente
ret
se mantiene cerrada para su procesamiento posterior, por cada función de aplazamiento.Esta es la implementación más rápida
fuente
Este código conserva intactas las secuencias de combinación de caracteres y también debería funcionar con entradas UTF-8 no válidas.
Podría ser un poco más eficiente si las primitivas unicode / norm permitieran iterar a través de los límites de una cadena sin asignar. Consulte también https://code.google.com/p/go/issues/detail?id=9055 .
fuente
[]byte
astring
Go, se reemplaza la "entrada UTF-8 no válida" por un punto de código válido\uFFFD
.string
no existe. Pero puede existir en a[]byte
.Si necesita manejar grupos de grafemas, use el módulo unicode o regexp.
fuente
str
se cotiza la salida, modifica la cotización inicial.También puede importar una implementación existente:
Luego:
O para invertir una cadena que incluya caracteres de combinación Unicode:
Estas implementaciones admiten el orden correcto de unicode multibyte y la combinación de caracteres cuando se invierte.
Nota: Las funciones de inversión de cadena incorporadas en muchos lenguajes de programación no conservan la combinación, y la identificación de caracteres combinados requiere mucho más tiempo de ejecución.
fuente
Seguramente no es la solución más eficiente en memoria, pero para una solución segura UTF-8 "simple", lo siguiente hará el trabajo y no romperá las runas.
En mi opinión, es el más legible y comprensible de la página.
fuente
Los siguientes dos métodos se ejecutan más rápido que la solución más rápida que conserva la combinación de caracteres , aunque eso no quiere decir que me esté perdiendo algo en mi configuración de referencia.
Segundo método inspirado en este
fuente
NOTA: Esta respuesta es de 2009, por lo que probablemente ya existen mejores soluciones.
Parece un poco "indirecto" y probablemente no muy eficiente, pero ilustra cómo se puede usar la interfaz de Reader para leer cadenas. Los IntVectors también parecen muy adecuados como búfer cuando se trabaja con cadenas utf8.
Sería aún más corto si se omite la parte de 'tamaño' y la inserción en el vector mediante Insertar, pero supongo que sería menos eficiente, ya que todo el vector debe retroceder uno cada vez que se agrega una nueva runa. .
Esta solución definitivamente funciona con caracteres utf8.
fuente
Una versión que creo que funciona en Unicode. Se basa en las funciones utf8.Rune:
fuente
runa es un tipo, así que úsala. Además, Go no usa punto y coma.
fuente
prueba el siguiente código:
para obtener más información, consulte http://golangcookbook.com/chapters/strings/reverse/
y http://www.dotnetperls.com/reverse-string-go
fuente
Para cadenas simples, es posible utilizar dicha construcción:
fuente
Aquí hay otra solución:
Sin embargo, la solución de yazu anterior es más elegante ya que invierte el
[]rune
corte en su lugar.fuente
Otra solución más (tm):
fuente
Prueba
Salida
fuente
fuente