Насколько я понимаю, приведенные ниже решения не работают с предварительно составленными или комбинированными символами, такими как передача a+´вместо á. Интересно, как это можно было учесть без нормализации.
вы не можете использовать len () в Go, чтобы узнать длину строки / массива / фрагмента и т. д. Вот почему? - len () в Go означает размер ввода в байтах. Это не соответствует его длине. - Не все руны utf8 имеют одинаковый размер. Это может быть 1, 2, 4 или 8. - Вы должны использовать метод RuneCountInString пакета unicode / ut8, чтобы получить длину руны.
Анвеш Чека
15
@AnveshChecka, это неверно. См. Golang.org/pkg/builtin/#len - len () на срезе определенно возвращает количество элементов, а не размер в байтах. Кусочек рун - правильный способ сделать это.
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)}
Мне нравится, как заставляют задуматься о кодировках.
Дьёрдь Андрасек
10
не по теме: почему это [болваны], а не [болваны]?
Джимми
2
Вау, что за двойное назначение при движении задним ходом? Интересный. Теперь представьте себе цепочку с нечетным количеством рун. К среднему обращаются по-особенному, но все же с правильным конечным результатом. :) Небольшая интересная оптимизация, о которой я бы сразу не подумал.
Kissaki
4
Я не понимаю, почему это преобразование в руны, почему бы и нет rune:=[]rune(input)?
siritinga 05
1
Вам не нужен первый цикл для диапазона. вывод: = [] руна (ввод); n: = len (output) И вам не нужна rune = rune [0: n]
dvallejo
30
Это работает, без всякой возни с функциями:
func Reverse(s string)(result string){for _,v := range s {
result =string(v)+ result}return}
Я бы назначил, i:=len(o)-1а затем свернул for в одну строку for _, c:=range s { o[i--]=c; }. Человек, которого я НЕНАВИЖУ, без круглых скобок - это разрешено:for(_, c:=range s) { o[i--]=c; }
Лоуренс Дол
Не могли бы вы объяснить, что делает _?
Лоуренс Дол
6
@Software_Monkey: o [i--] = c не допускается в Go. - и ++ - это утверждения, а не выражения. _ означает отбросить (игнорировать) эту переменную.
Рэнди Сугианто 'Yuku'
1
с go 1.1+ он возвращает ошибку в строке ([] int), если вместо o используется тип руны [], все работает
Otuk
1
@yuku: Все еще терпит неудачу на 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)}
Спасибо за разъяснение отличия от stackoverflow.com/a/10030772/3093387 - кажется, что эти два решения отличаются тем, как они обрабатывают строки, такие как «bròwn».
josliber
Спасибо за упоминание решения Rosettacode, которое обрабатывает объединение символов
дольмен
11
Я заметил этот вопрос, когда Саймон опубликовал свое решение, которое, поскольку строки неизменяемы, очень неэффективно. Другие предлагаемые решения также ошибочны; они не работают или неэффективны.
Вот эффективное решение, которое работает, за исключением случаев, когда строка не является допустимой UTF-8 или строка содержит комбинирующие символы.
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: Нет, return string(runes)работает не во всех случаях.
peterSO
не могли бы вы объяснить немного подробнее, почему это так? Я сделал короткую программу, и она там работает, но, может быть, те случаи, о которых вы говорите, там не срабатывают? play.golang.org/p/yk1sAwFjol
1
@Tommy: Ваша короткая программа просто демонстрирует, что символ NUL является NOP при отправке на принтер или терминал. Ваша функция Reverse2 не работает для строк в кодировке, отличной от ASCII UTF-8. Я пересмотрел вашу короткую программу, чтобы она стала действительным тестом: play.golang.org/p/Ic5G5QEO93
peterSO
Еще одно неправильное «решение», которое неправильно обрабатывает комбинирование символов.
дольмен
10
Здесь слишком много ответов. Некоторые из них - явные дубликаты. Но даже из левого варианта сложно выбрать лучшее решение.
Я просмотрел ответы, выбросил тот, который не работает для юникода, а также удалил дубликаты. Я сравнил выживших, чтобы найти самых быстрых. Итак, вот результаты с атрибуцией (если вы заметили ответы, которые я пропустил, но которые стоит добавить, не стесняйтесь изменять тест):
По какой-то причине я не могу добавить тест, поэтому вы можете его скопировать PlayGround(там нельзя запускать тесты). Переименуйте и запуститеgo test -bench=.
Ни одно из этих "решений" не обрабатывает правильно совмещение отметок .
дольмен
6
Я написал следующую Reverseфункцию, которая учитывает кодировку UTF8 и комбинированные символы:
// 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)}
Я сделал все возможное, чтобы сделать его максимально эффективным и читаемым. Идея проста: пройти через руны в поисках комбинированных символов, а затем поменять местами руны объединенных персонажей. После того, как мы покрыли их все, переверните руны всей цепочки также на месте.
Скажем, мы хотим перевернуть эту строку bròwn. òПредставлены два рун, один для oи один для этого юникода \u0301a, представляемого «могила».
Для простоты представим строку вот так bro'wn. Первое, что мы делаем, это ищем комбинированные символы и меняем их местами. Итак, теперь у нас есть строка br'own. Наконец, мы переворачиваем всю строку и получаем nwo'rb. Это возвращается нам какnwòrb
//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
Использование strings.Builder примерно в 3 раза быстрее, чем использование конкатенации строк
Я почти уверен, что это не самое быстрое решение, но оно показывает, как возвращаемая переменная retзакрывается для дальнейшей обработки каждой функцией отсрочки.
Владимир Бауэр
Медленно и неправильно обрабатывает объединение символов.
дольмен
1
Не знаю, насколько это быстро, но красиво.
donatJ
Производительность этого может быть улучшена в Go 1.14. По крайней мере, в примечаниях к выпуску утверждается, что у них нет накладных расходов на отсрочку.
Владимир Бауэр
3
Основываясь на исходном предложении Stephan202 и, похоже, работает для строк 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,"");}
Альтернативный вариант, без использования строкового пакета, но не «безопасный для юникода»:
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]}returnstring( b );}
+1. Это работает. Но я должен сказать, что довольно странно (на данный момент), что разделение и объединение необходимо для такой простой задачи ...
Stephan202
@martin: извините за редактирование. Я случайно вставил свой обновленный ответ в ваш вопрос ... мне очень стыдно .
Stephan202
@ Стефан - без проблем. Я добавил альтернативное решение, основанное на функции Bytes пакета strings.
Мартин Клейтон
@Nosradena: Я откатился назад в течение той же минуты (я был удивлен, увидев, что Мартин обновил свой ответ точно таким же текстом, который я только что написал ... и затем меня осенило;)
Stephan202
@martin: вторая версия выглядит лучше, если вы спросите меня :)
Stephan202
3
Это самая быстрая реализация
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)}}
В строковых значениях нет такого «недопустимого ввода UTF-8»: при преобразовании из []byteв stringGo заменяет «недопустимый ввод UTF-8» на допустимый код \uFFFD.
дольмен
Я не понимаю приведенный выше комментарий. Вы говорите, что поведение этого кода неверно, когда он представлен строкой, содержащей недопустимый UTF-8?
Rog
Нет. Я говорю, что недопустимый UTF-8 в Go stringне существует. Но он может существовать в []byte.
дольмен
Строка Go может содержать ровно столько недопустимого utf-8, сколько байт []. Например: play.golang.org/p/PG0I4FJfEN
Rog
2
Если вам нужно обрабатывать кластеры графем, используйте модуль unicode или 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
}
Я хочу дать вам 1'000 голосов за. Все другие реализации на этой странице неправильно меняют СТРОКУ (СТРОКА НЕ является последовательностью символов).
Stefan Steiger
Это не работает. Если вы дважды перевернете строку, вы не получите исходную строку. Ведущий комбинированный диэрезис (\ u0308), используемый в этом примере, объединяется с предыдущими символами, образуя двойной умляут «а» при обратном. Если strвыводится в кавычках, это изменяет начальную цитату!
Джошуа Колден
2
Вы также можете импортировать существующую реализацию:
import"4d63.com/strrev"
Затем:
strrev.Reverse("abåd")// returns "dåba"
Или перевернуть строку, содержащую объединяющие символы Unicode:
Эти реализации поддерживают правильный порядок многобайтовых символов Юникода и расчесывание символов в обратном порядке.
Примечание. Встроенные функции реверса строк во многих языках программирования не сохраняют комбинирование, а идентификация комбинируемых символов требует значительно большего времени выполнения.
Конечно, это не самое эффективное решение с точки зрения памяти, но для «простого» безопасного решения UTF-8 следующее выполнит свою работу и не сломает руны.
На мой взгляд он самый читаемый и понятный на странице.
func reverseStr(str string)(outstring){for _, s := range str {out=string(s)+out}return}
Вот чего вам не хватает в вашем тесте: ваше решение работает быстрее, потому что оно не сохраняет комбинируемые символы. Сравнивать их просто несправедливо.
дольмен
1
ПРИМЕЧАНИЕ. Этот ответ относится к 2009 году, поэтому, вероятно, на данный момент существуют лучшие решения.
Выглядит немного «окольным путем» и, вероятно, не очень эффективно, но иллюстрирует, как интерфейс Reader может использоваться для чтения из строк. IntVectors также кажутся очень подходящими в качестве буферов при работе со строками utf8.
Это было бы еще короче, если бы не было части `` размер '' и вставка в вектор с помощью Insert, но я предполагаю, что это будет менее эффективно, так как весь вектор тогда нужно отодвигать на единицу каждый раз, когда добавляется новая руна. .
Это решение определенно работает с символами 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());}
руна - это тип, поэтому используйте ее. Более того, Go не использует точки с запятой.
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,"")}
Тест
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)}}
Вывод
Input: GO je úžasné!Output:!énsažú ej OG
PASS
ok github.com/alesr/reverse-string0.098s
a+´
вместоá
. Интересно, как это можно было учесть без нормализации.Ответы:
В Go1 руна - это встроенный тип.
источник
Расс Кокс из списка рассылки golang-nut предлагает
источник
rune:=[]rune(input)
?Это работает, без всякой возни с функциями:
источник
Это работает со строками Unicode, учитывая 2 вещи:
Итак, вот оно:
источник
i:=len(o)-1
а затем свернул for в одну строкуfor _, c:=range s { o[i--]=c; }
. Человек, которого я НЕНАВИЖУ, без круглых скобок - это разрешено:for(_, c:=range s) { o[i--]=c; }
Примеры проектов из Go: golang / example / stringutil / reverse.go , Эндрю Герранд
Перейти на площадку для переворота струны
После изменения строки «bròwn» правильным результатом должно быть «nwòrb», а не «nẁorb».
Обратите внимание на могилу над буквой o.
Для сохранения Unicode-сочетания символов, таких как «as⃝df̅» с обратным результатом «f̅ds⃝a»,
обратитесь к другому коду, указанному ниже:
http://rosettacode.org/wiki/Reverse_a_string#Go
источник
Я заметил этот вопрос, когда Саймон опубликовал свое решение, которое, поскольку строки неизменяемы, очень неэффективно. Другие предлагаемые решения также ошибочны; они не работают или неэффективны.
Вот эффективное решение, которое работает, за исключением случаев, когда строка не является допустимой UTF-8 или строка содержит комбинирующие символы.
источник
return string(runes)
работает не во всех случаях.Здесь слишком много ответов. Некоторые из них - явные дубликаты. Но даже из левого варианта сложно выбрать лучшее решение.
Я просмотрел ответы, выбросил тот, который не работает для юникода, а также удалил дубликаты. Я сравнил выживших, чтобы найти самых быстрых. Итак, вот результаты с атрибуцией (если вы заметили ответы, которые я пропустил, но которые стоит добавить, не стесняйтесь изменять тест):
Итак, вот самый быстрый метод от rmuller :
По какой-то причине я не могу добавить тест, поэтому вы можете его скопировать PlayGround(там нельзя запускать тесты). Переименуйте и запустите
go test -bench=.
источник
Я написал следующую
Reverse
функцию, которая учитывает кодировку UTF8 и комбинированные символы:Я сделал все возможное, чтобы сделать его максимально эффективным и читаемым. Идея проста: пройти через руны в поисках комбинированных символов, а затем поменять местами руны объединенных персонажей. После того, как мы покрыли их все, переверните руны всей цепочки также на месте.
Скажем, мы хотим перевернуть эту строку
bròwn
.ò
Представлены два рун, один дляo
и один для этого юникода\u0301a
, представляемого «могила».Для простоты представим строку вот так
bro'wn
. Первое, что мы делаем, это ищем комбинированные символы и меняем их местами. Итак, теперь у нас есть строкаbr'own
. Наконец, мы переворачиваем всю строку и получаемnwo'rb
. Это возвращается нам какnwòrb
Вы можете найти его здесь https://github.com/shomali11/util, если хотите его использовать.
Вот несколько тестовых примеров, чтобы показать несколько разных сценариев:
источник
Использование strings.Builder примерно в 3 раза быстрее, чем использование конкатенации строк
источник
Вот совсем другой, я бы сказал, более функциональный подход, не перечисленный среди других ответов:
источник
ret
закрывается для дальнейшей обработки каждой функцией отсрочки.Основываясь на исходном предложении Stephan202 и, похоже, работает для строк Unicode:
Альтернативный вариант, без использования строкового пакета, но не «безопасный для юникода»:
источник
Это самая быстрая реализация
источник
Этот код сохраняет последовательности комбинирования символов без изменений и также должен работать с недопустимым вводом UTF-8.
Было бы немного эффективнее, если бы примитивы юникода / нормы позволяли выполнять итерацию через границы строки без выделения. См. Также https://code.google.com/p/go/issues/detail?id=9055 .
источник
[]byte
вstring
Go заменяет «недопустимый ввод UTF-8» на допустимый код\uFFFD
.string
не существует. Но он может существовать в[]byte
.Если вам нужно обрабатывать кластеры графем, используйте модуль unicode или regexp.
источник
str
выводится в кавычках, это изменяет начальную цитату!Вы также можете импортировать существующую реализацию:
Затем:
Или перевернуть строку, содержащую объединяющие символы Unicode:
Эти реализации поддерживают правильный порядок многобайтовых символов Юникода и расчесывание символов в обратном порядке.
Примечание. Встроенные функции реверса строк во многих языках программирования не сохраняют комбинирование, а идентификация комбинируемых символов требует значительно большего времени выполнения.
источник
Конечно, это не самое эффективное решение с точки зрения памяти, но для «простого» безопасного решения UTF-8 следующее выполнит свою работу и не сломает руны.
На мой взгляд он самый читаемый и понятный на странице.
источник
Следующие два метода работают быстрее, чем самое быстрое решение, сохраняющее комбинирование символов , хотя это не значит, что мне чего-то не хватает в моей настройке теста.
Второй метод, вдохновленный этим
источник
ПРИМЕЧАНИЕ. Этот ответ относится к 2009 году, поэтому, вероятно, на данный момент существуют лучшие решения.
Выглядит немного «окольным путем» и, вероятно, не очень эффективно, но иллюстрирует, как интерфейс Reader может использоваться для чтения из строк. IntVectors также кажутся очень подходящими в качестве буферов при работе со строками utf8.
Это было бы еще короче, если бы не было части `` размер '' и вставка в вектор с помощью Insert, но я предполагаю, что это будет менее эффективно, так как весь вектор тогда нужно отодвигать на единицу каждый раз, когда добавляется новая руна. .
Это решение определенно работает с символами utf8.
источник
Версия, которая, как мне кажется, работает в Юникоде. Он построен на функциях utf8.Rune:
источник
руна - это тип, поэтому используйте ее. Более того, Go не использует точки с запятой.
источник
попробуйте ниже код:
для получения дополнительной информации проверьте http://golangcookbook.com/chapters/strings/reverse/
и http://www.dotnetperls.com/reverse-string-go
источник
Для простых строк можно использовать такую конструкцию:
источник
Простой штрих с
rune
:источник
Вот еще одно решение:
Однако вышеприведенное решение Язу более элегантно, поскольку он переворачивает
[]rune
срез на место.источник
Еще одно решение (tm):
источник
Тест
Вывод
источник
источник