Bagaimana cara membalikkan string sederhana di Go?
Bagaimana cara membalikkan string sederhana di Go?
Jawaban:
Di Go1 rune adalah tipe bawaan.
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, di milis golang-nut , menyarankan
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)
?
Ini berfungsi, tanpa semua penyia-nyiaan dengan fungsi:
func Reverse(s string) (result string) {
for _,v := range s {
result = string(v) + result
}
return
}
Ini bekerja pada string unicode dengan mempertimbangkan 2 hal:
Jadi begini:
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
dan kemudian melipat untuk menjadi satu baris for _, c:=range s { o[i--]=c; }
. Man I HATE karena tanpa tanda kurung - apakah ini diizinkan:for(_, c:=range s) { o[i--]=c; }
Dari proyek contoh Go: golang / example / stringutil / reverse.go , oleh Andrew Gerrand
/*
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)
}
Pergi Playground untuk membalikkan string
Setelah membalikkan string "bròwn", hasil yang benar haruslah "nwòrb", bukan "nẁorb".
Perhatikan kuburan di atas huruf o.
Untuk mempertahankan Unicode yang menggabungkan karakter seperti "as⃝df̅" dengan hasil terbalik "f̅ds⃝a",
lihat kode lain yang tercantum di bawah ini:
Saya memperhatikan pertanyaan ini ketika Simon memposting solusinya yang, karena string tidak dapat diubah, sangat tidak efisien. Solusi lain yang diusulkan juga cacat; mereka tidak bekerja atau tidak efisien.
Berikut adalah solusi efisien yang berfungsi, kecuali jika string tersebut bukan UTF-8 yang valid atau string berisi kombinasi karakter.
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)
tidak bekerja untuk semua kasus.
Ada terlalu banyak jawaban di sini. Beberapa di antaranya merupakan duplikat yang jelas. Tetapi bahkan dari yang kiri, sulit untuk memilih solusi terbaik.
Jadi saya memeriksa jawabannya, membuang yang tidak berfungsi untuk unicode dan juga menghapus duplikat. Saya membandingkan orang yang selamat untuk menemukan yang tercepat. Jadi, inilah hasil dengan atribusi (jika Anda melihat jawaban yang saya lewatkan, tetapi layak ditambahkan, silakan memodifikasi tolok ukur):
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
Jadi inilah metode tercepat oleh rmuller :
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)
}
Untuk beberapa alasan saya tidak dapat menambahkan patokan, jadi Anda dapat menyalinnya dari PlayGround(Anda tidak dapat menjalankan tes di sana). Ubah namanya dan jalankango test -bench=.
Saya menulis Reverse
fungsi berikut yang menghormati pengkodean UTF8 dan karakter gabungan:
// 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)
}
Saya melakukan yang terbaik untuk membuatnya seefisien dan semudah mungkin. Idenya sederhana, melintasi rune mencari karakter gabungan kemudian membalikkan rune karakter gabungan di tempat. Setelah kita menutupi semuanya, balikkan rune dari seluruh string juga di tempatnya.
Katakanlah kami ingin membalikkan string ini bròwn
. Itu ò
diwakili oleh dua rune, satu untuk the o
dan satu untuk unicode ini \u0301a
yang mewakili "kuburan".
Untuk kesederhanaan, mari kita gambarkan string seperti ini bro'wn
. Hal pertama yang kami lakukan adalah mencari karakter gabungan dan membalikkannya. Jadi sekarang kita punya tali br'own
. Akhirnya, kami membalikkan seluruh string dan berakhir dengan nwo'rb
. Ini dikembalikan kepada kami sebagainwòrb
Anda dapat menemukannya di sini https://github.com/shomali11/util jika Anda ingin menggunakannya.
Berikut beberapa kasus uji untuk menunjukkan beberapa skenario yang berbeda:
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")
}
Membangun di atas saran asli Stephan202, dan tampaknya berfungsi untuk string 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, "" );
}
Alternatifnya, tidak menggunakan paket string, tetapi bukan 'unicode-safe':
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
Menggunakan strings.Builder sekitar 3 kali lebih cepat daripada menggunakan penggabungan string
Ini sangat berbeda, saya akan mengatakan pendekatan yang lebih fungsional, tidak tercantum di antara jawaban lain:
func reverse(s string) (ret string) {
for _, v := range s {
defer func(r rune) { ret += string(r) }(v)
}
return
}
ret
disimpan dalam penutupan untuk diproses lebih lanjut, dengan setiap fungsi penangguhan.
Ini adalah implementasi tercepat
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)
}
}
Kode ini mempertahankan urutan penggabungan karakter secara utuh, dan harus bekerja dengan masukan UTF-8 yang tidak valid juga.
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)
}
Ini bisa menjadi sedikit lebih efisien jika primitif unicode / norm mengizinkan iterasi melalui batas-batas string tanpa mengalokasikan. Lihat juga https://code.google.com/p/go/issues/detail?id=9055 .
[]byte
ke string
Go menggantikan "input UTF-8 yang tidak valid" dengan titik kode yang valid \uFFFD
.
string
tidak ada. Tapi itu bisa ada di []byte
.
Jika Anda perlu menangani cluster grafem, gunakan modul unicode atau 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
}
str
output dikutip, itu mengubah kutipan terkemuka!
Anda juga dapat mengimpor implementasi yang sudah ada:
import "4d63.com/strrev"
Kemudian:
strrev.Reverse("abåd") // returns "dåba"
Atau untuk membalikkan string termasuk unicode yang menggabungkan karakter:
strrev.ReverseCombining("abc\u0301\u031dd") // returns "d\u0301\u031dcba"
Implementasi ini mendukung pengurutan yang benar dari multibyte unicode dan karakter combing ketika dibalik.
Catatan: Fungsi pembalikan string bawaan dalam banyak bahasa pemrograman tidak mempertahankan penggabungan, dan mengidentifikasi penggabungan karakter memerlukan waktu eksekusi yang jauh lebih lama.
Ini pasti bukan solusi yang paling hemat memori, tetapi untuk solusi aman UTF-8 "sederhana" berikut ini akan menyelesaikan pekerjaan dan tidak merusak rune.
Menurut pendapat saya, ini paling mudah dibaca dan dipahami di halaman ini.
func reverseStr(str string) (out string) {
for _, s := range str {
out = string(s) + out
}
return
}
Dua metode berikut berjalan lebih cepat daripada solusi tercepat yang mempertahankan penggabungan karakter , meskipun itu tidak berarti saya kehilangan sesuatu dalam pengaturan benchmark saya.
//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
Metode kedua terinspirasi oleh ini
//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
CATATAN: Jawaban ini dari 2009, jadi mungkin ada solusi yang lebih baik di luar sana sekarang.
Tampak agak 'bundaran', dan mungkin tidak terlalu efisien, tetapi menggambarkan bagaimana antarmuka Reader dapat digunakan untuk membaca dari string. IntVectors juga tampaknya sangat cocok sebagai buffer saat bekerja dengan string utf8.
Ini akan menjadi lebih pendek ketika meninggalkan bagian 'ukuran', dan penyisipan ke dalam vektor dengan Sisipkan, tapi saya rasa itu akan kurang efisien, karena seluruh vektor kemudian perlu didorong kembali oleh satu setiap kali rune baru ditambahkan .
Solusi ini pasti berfungsi dengan karakter 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());
}
Sebuah versi yang menurut saya berfungsi pada unicode. Itu dibangun di atas fungsi 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);
}
rune adalah tipe, jadi gunakanlah. Selain itu, Go tidak menggunakan titik koma.
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))
}
coba kode di bawah ini:
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"))
}
untuk info lebih lanjut, periksa http://golangcookbook.com/chapters/strings/reverse/
dan http://www.dotnetperls.com/reverse-string-go
Untuk string sederhana dimungkinkan untuk menggunakan konstruksi seperti itu:
func Reverse(str string) string {
if str != "" {
return Reverse(str[1:]) + str[:1]
}
return ""
}
Ini solusi lainnya:
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)
}
Namun, solusi yazu di atas lebih elegan karena ia membalikkan []rune
potongan pada tempatnya.
Namun Solusi Lain (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, "")
}
Uji
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)
}
}
Keluaran
Input: GO je úžasné!
Output: !énsažú ej OG
PASS
ok github.com/alesr/reverse-string 0.098s
a+´
bukaná
. Saya bertanya-tanya bagaimana hal itu dapat diperhitungkan, tanpa menormalkannya.