Go'da basit bir dizeyi nasıl tersine çevirebiliriz?
Go'da basit bir dizeyi nasıl tersine çevirebiliriz?
Yanıtlar:
Go1'de rune yerleşik bir tiptir.
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 golang-fındık posta listesinde , anlaşılacağı
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)
?
Bu, işlevlerle uğraşmadan çalışır:
func Reverse(s string) (result string) {
for _,v := range s {
result = string(v) + result
}
return
}
Bu, 2 şeyi dikkate alarak unicode dizeleri üzerinde çalışır:
İşte başlıyor:
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
ve sonra tek bir satıra katlardım for _, c:=range s { o[i--]=c; }
. Adamım, parantez olmadan nefret ediyorum - buna izin verilir:for(_, c:=range s) { o[i--]=c; }
Gönderen golang / example / stringutil / reverse.go: Git örnek projelerin Andrew Gerrand tarafından
/*
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)
}
Bir dizeyi ters çevirmek için Playground'a gidin
"Bròwn" dizesini tersine çevirdikten sonra, doğru sonuç "nẁorb" değil "nwòrb" olmalıdır.
O harfinin üzerindeki mezara dikkat edin.
Ters sonucu "f̅ds⃝a" olan "as⃝df̅" gibi Unicode birleşik karakterleri korumak için,
lütfen aşağıda listelenen başka bir koda bakın:
Simon , dizeler değişmez olduğu için çok verimsiz olan çözümünü yayınladığında bu soruyu fark ettim . Önerilen diğer çözümler de kusurludur; çalışmıyorlar veya verimsizler.
Dize geçerli UTF-8 olmadığı veya dizenin birleştirici karakterler içermesi dışında çalışan verimli bir çözüm aşağıda verilmiştir.
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)
her durumda çalışmaz.
Burada çok fazla cevap var. Bazıları açık kopyalar. Ancak soldan bile en iyi çözümü seçmek zor.
Bu yüzden cevapları gözden geçirdim, unicode için çalışmayan ve aynı zamanda kopyaları sildim. En hızlı olanı bulmak için hayatta kalanları kıyasladım. İşte atıfta bulunan sonuçlar (gözden kaçırdığım ancak eklemeye değer yanıtları fark ederseniz, karşılaştırmayı değiştirmekten çekinmeyin):
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
İşte rmuller'ın en hızlı yöntemi :
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)
}
Bazı nedenlerden dolayı bir kıyaslama ekleyemiyorum, bu yüzden onu kopyalayabilirsiniz PlayGround(orada testler çalıştıramazsınız). Yeniden adlandırın ve çalıştırıngo test -bench=.
Reverse
UTF8 kodlamasına ve birleşik karakterlere saygı duyan aşağıdaki işlevi yazdım :
// 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)
}
Bunu olabildiğince verimli ve okunabilir hale getirmek için elimden geleni yaptım. Fikir basittir, birleşik karakterleri aramak için runelerin arasından geçin, ardından birleşik karakterlerin runlarını yerinde tersine çevirin. Hepsini örttüğümüzde, tüm dizinin rünlerini de yerinde ters çevirin.
Bu dizeyi tersine çevirmek istediğimizi varsayalım bròwn
. ò
İki runes için biri tarafından temsil edilir o
ve bu unicode diğeri \u0301a
"vahim" temsil eder.
Basit olması için, dizeyi şu şekilde temsil edelim bro'wn
. Yaptığımız ilk şey, birleşik karakterleri aramak ve onları tersine çevirmek. Şimdi ipimiz var br'own
. Son olarak, tüm dizgiyi tersine çeviririz ve sonunda nwo'rb
. Bu bize şu şekilde iade edilirnwòrb
Kullanmak isterseniz burada https://github.com/shomali11/util bulabilirsiniz .
Birkaç farklı senaryoyu gösteren bazı test senaryoları şunlardır:
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")
}
Stephan202'nin orijinal önerisini temel alan ve unicode dizeleri için işe yaradığı görülüyor:
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, "" );
}
Alternatif, dizeler paketi kullanmadan, ancak 'unicode güvenli' değil:
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
Dizeleri kullanmak. Oluşturucu, dize birleştirme kullanmaktan yaklaşık 3 kat daha hızlıdır
İşte oldukça farklı, diğer cevaplar arasında listelenmeyen daha işlevsel bir yaklaşım söyleyebilirim:
func reverse(s string) (ret string) {
for _, v := range s {
defer func(r rune) { ret += string(r) }(v)
}
return
}
ret
her erteleme işlevi tarafından daha fazla işlem için nasıl kapalı tutulduğunu gösteriyor .
Bu en hızlı uygulama
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)
}
}
Bu kod, birleşik karakter dizilerini bozulmadan korur ve geçersiz UTF-8 girdisiyle de çalışmalıdır.
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)
}
Unicode / norm ilkelleri, ayırmadan bir dizgenin sınırları boyunca yinelemeye izin verirse, biraz daha verimli olabilirdi. Ayrıca bkz . Https://code.google.com/p/go/issues/detail?id=9055 .
[]byte
den string
Go'ya dönüştürürken, "geçersiz UTF-8 girdisini" geçerli bir kod noktasıyla değiştirir \uFFFD
.
string
. Go'da geçersiz UTF-8'in olmadığını söylüyorum . Ama bir []byte
.
Grapheme kümelerini işlemeniz gerekiyorsa, unicode veya regexp modülünü kullanın.
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
çıkış alıntı o lider alıntı değiştirir!
Ayrıca mevcut bir uygulamayı da içe aktarabilirsiniz:
import "4d63.com/strrev"
Sonra:
strrev.Reverse("abåd") // returns "dåba"
Veya unicode birleştiren karakterler içeren bir dizeyi ters çevirmek için:
strrev.ReverseCombining("abc\u0301\u031dd") // returns "d\u0301\u031dcba"
Bu uygulamalar, unicode çok baytının doğru sıralanmasını ve tersine çevrildiğinde karakterlerin taranmasını destekler.
Not: Birçok programlama dilindeki yerleşik dizi ters işlevleri, birleştirmeyi korumaz ve birleşik karakterlerin tanımlanması, önemli ölçüde daha fazla yürütme süresi gerektirir.
Kesinlikle bellek açısından en verimli çözüm değil, ancak "basit" UTF-8 güvenli bir çözüm için aşağıdakiler işi bitirecek ve runları bozmayacaktır.
Bence sayfadaki en okunaklı ve anlaşılır olanı.
func reverseStr(str string) (out string) {
for _, s := range str {
out = string(s) + out
}
return
}
Aşağıdaki iki yöntem , karakterleri birleştirmeyi koruyan en hızlı çözümden daha hızlı çalışır , ancak bu, kıyaslama kurulumumda bir şeyleri kaçırdığım anlamına gelmez.
//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
İkinci yöntem esinlenerek bu
//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
NOT: Bu cevap 2009 yılına aittir, bu nedenle şimdiye kadar muhtemelen daha iyi çözümler vardır.
Biraz 'dolambaçlı' görünüyor ve muhtemelen çok verimli değil, ancak Reader arayüzünün dizelerden okumak için nasıl kullanılabileceğini gösteriyor. IntVector'lar ayrıca utf8 dizeleriyle çalışırken tampon olarak çok uygun görünmektedir.
'Boyut' kısmını dışarıda bıraktığınızda ve Ekleme ile vektöre yerleştirildiğinde daha da kısa olacaktır, ancak sanırım bu daha az verimli olacaktır, çünkü daha sonra tüm vektörün yeni bir rune eklendiğinde bir tane geri itilmesi gerekir. .
Bu çözüm kesinlikle utf8 karakterleriyle çalışır.
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());
}
Unicode üzerinde çalıştığını düşündüğüm bir sürüm. Utf8.Rune işlevleri üzerine kurulmuştur:
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 bir türdür, bu yüzden onu kullanın. Dahası, Go noktalı virgül kullanmaz.
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))
}
aşağıdaki kodu deneyin:
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"))
}
daha fazla bilgi için http://golangcookbook.com/chapters/strings/reverse/
ve http://www.dotnetperls.com/reverse-string-go
Basit dizeler için böyle bir yapıyı kullanmak mümkündür:
func Reverse(str string) string {
if str != "" {
return Reverse(str[1:]) + str[:1]
}
return ""
}
İşte başka bir çözüm:
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)
}
Bununla birlikte, yazu'nun yukarıdaki çözümü, []rune
dilimi yerinde ters çevirdiği için daha zariftir .
Yine Başka Bir Çözüm (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, "")
}
Ölçek
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)
}
}
Çıktı
Input: GO je úžasné!
Output: !énsažú ej OG
PASS
ok github.com/alesr/reverse-string 0.098s
a+´
yerine vermek gibi önceden oluşturulmuş veya birleştirilen karakterlerle çalışmıyorá
. Normalleştirmeden bunun nasıl dikkate alınabileceğini merak ediyorum.