เราจะย้อนกลับสตริงง่ายๆใน Go ได้อย่างไร?
คำตอบ:
ใน Go1 rune เป็นประเภท builtin
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 ในรายชื่อผู้รับจดหมายของโกแลงนัทแนะนำ
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)
?
ใช้งานได้โดยไม่ต้องยุ่งเกี่ยวกับฟังก์ชัน:
func Reverse(s string) (result string) {
for _,v := range s {
result = string(v) + result
}
return
}
สิ่งนี้ใช้ได้กับสตริง Unicode โดยพิจารณา 2 สิ่ง:
นี่คือ:
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
for _, c:=range s { o[i--]=c; }
ผู้ชายที่ฉันเกลียดการไม่มีวงเล็บ - อนุญาตหรือไม่:for(_, c:=range s) { o[i--]=c; }
จากโครงการตัวอย่าง Go: golang / example / stringutil / reverse.goโดย 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)
}
ไปที่ Playground เพื่อย้อนกลับสตริง
หลังจากย้อนกลับสตริง "bròwn" ผลลัพธ์ที่ถูกต้องควรเป็น "nwòrb" ไม่ใช่ "nẁorb"
สังเกตหลุมฝังศพเหนือตัวอักษร o
สำหรับการเก็บรักษา Unicode ที่รวมอักขระเช่น "as⃝df̅" ด้วยผลลัพธ์ย้อนกลับ "f̅ds⃝a"
โปรดดูรหัสอื่นที่แสดงด้านล่าง:
ฉันสังเกตเห็นคำถามนี้เมื่อSimonโพสต์วิธีแก้ปัญหาของเขาซึ่งเนื่องจากสตริงไม่เปลี่ยนรูปจึงไม่มีประสิทธิภาพมาก แนวทางแก้ไขปัญหาอื่น ๆ ที่นำเสนอก็มีข้อบกพร่องเช่นกัน ไม่ทำงานหรือไม่มีประสิทธิภาพ
นี่คือวิธีแก้ปัญหาที่มีประสิทธิภาพที่ใช้งานได้ยกเว้นเมื่อสตริงไม่ใช่ UTF-8 ที่ถูกต้องหรือสตริงมีอักขระรวมกัน
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)
ไม่ใช้ได้ทุกกรณี
มีคำตอบมากเกินไปที่นี่ บางส่วนเป็นรายการที่ซ้ำกันชัดเจน แต่ถึงแม้จะเลือกจากทางซ้ายก็ยากที่จะเลือกวิธีแก้ปัญหาที่ดีที่สุด
ดังนั้นฉันจึงอ่านคำตอบทิ้งคำตอบที่ใช้ไม่ได้กับ Unicode และลบรายการที่ซ้ำกันออกไป ฉันเปรียบเทียบผู้รอดชีวิตเพื่อค้นหาผู้ที่เร็วที่สุด ดังนั้นนี่คือผลลัพธ์พร้อมการระบุแหล่งที่มา (หากคุณสังเกตเห็นคำตอบที่ฉันพลาดไป แต่คุ้มค่าที่จะเพิ่มอย่าลังเลที่จะแก้ไขเกณฑ์มาตรฐาน):
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
ดังนั้นนี่คือวิธีที่เร็วที่สุดโดย 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)
}
ด้วยเหตุผลบางอย่างฉันไม่สามารถเพิ่มเกณฑ์มาตรฐานได้ดังนั้นคุณสามารถคัดลอกจากPlayGround(คุณไม่สามารถเรียกใช้การทดสอบที่นั่นได้) เปลี่ยนชื่อและเรียกใช้go test -bench=.
ฉันเขียน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, 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)
}
ฉันพยายามอย่างเต็มที่เพื่อให้มีประสิทธิภาพและอ่านง่ายที่สุด แนวคิดง่ายๆคือสำรวจผ่านอักษรรูนเพื่อค้นหาอักขระที่รวมกันแล้วย้อนกลับรูนของอักขระที่รวมเข้าด้วยกัน เมื่อเราครอบคลุมทั้งหมดแล้วให้ย้อนรูนของสตริงทั้งหมดเข้าที่ด้วย
สมมติว่าเราต้องการย้อนกลับสตริงbròwn
นี้ สัญลักษณ์ò
นี้แสดงด้วยอักษรรูนสองตัวอันหนึ่งสำหรับo
และอีกอันสำหรับยูนิโคดนี้\u0301a
ที่แสดงถึง "หลุมศพ"
bro'wn
สำหรับความเรียบง่ายให้เป็นตัวแทนของสายเช่นนี้ สิ่งแรกที่เราทำคือมองหาอักขระที่รวมกันแล้วย้อนกลับ ตอนนี้เรามีสตริงbr'own
แล้ว สุดท้ายเราย้อนกลับสตริงทั้งหมดและลงท้ายด้วยnwo'rb
. สิ่งนี้จะส่งกลับมาให้เราเป็นnwòrb
คุณสามารถค้นหาได้ที่นี่https://github.com/shomali11/utilหากคุณต้องการใช้
ต่อไปนี้เป็นกรณีทดสอบเพื่อแสดงสถานการณ์ที่แตกต่างกันสองสามสถานการณ์:
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")
}
🙏2️⃣👌👁
👁👌2️⃣🙏
ส่วนใหญ่คำตอบอื่น ๆ 👁👌⃣️2🙏
กลับมา paiza.io/projects/K8_kOmxn-cGRR3ksh1vFtw
//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
การใช้สตริง Builder เร็วกว่าการใช้การต่อสตริงประมาณ 3 เท่า
ที่นี่ค่อนข้างแตกต่างกันฉันจะพูดถึงแนวทางการทำงานมากกว่าซึ่งไม่ได้ระบุไว้ในคำตอบอื่น ๆ :
func reverse(s string) (ret string) {
for _, v := range s {
defer func(r rune) { ret += string(r) }(v)
}
return
}
ret
ถูกปิดไว้เพื่อการประมวลผลต่อไปอย่างไรโดยแต่ละฟังก์ชัน defer
สร้างตามข้อเสนอแนะดั้งเดิมของ 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, "" );
}
ทางเลือกอื่นไม่ใช้แพ็คเกจสตริง แต่ไม่ใช่ '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 );
}
นี่คือการใช้งานที่เร็วที่สุด
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)
}
}
รหัสนี้เก็บรักษาลำดับของการรวมอักขระที่เหมือนเดิมและควรใช้กับอินพุต UTF-8 ที่ไม่ถูกต้องด้วย
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)
}
อาจมีประสิทธิภาพมากกว่านี้เล็กน้อยหากไพรเมติกยูนิโคด / บรรทัดฐานอนุญาตให้วนซ้ำผ่านขอบเขตของสตริงโดยไม่ต้องจัดสรร ดูเพิ่มเติมhttps://code.google.com/p/go/issues/detail?id=9055
[]byte
ที่จะstring
ไปแทนที่ "ไม่ถูกต้อง UTF-8 การป้อนข้อมูล" \uFFFD
โดยจุดโค้ดที่ถูกต้อง
string
ไม่มีอยู่ แต่สามารถมีอยู่ในไฟล์[]byte
.
หากคุณต้องการจัดการกับคลัสเตอร์ grapheme ให้ใช้โมดูล 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)
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
เอาต์พุตที่ยกมามันจะปรับเปลี่ยนคำพูดชั้นนำ!
คุณยังสามารถนำเข้าการใช้งานที่มีอยู่:
import "4d63.com/strrev"
จากนั้น:
strrev.Reverse("abåd") // returns "dåba"
หรือเพื่อย้อนกลับสตริงรวมถึงอักขระที่รวมยูนิโคด:
strrev.ReverseCombining("abc\u0301\u031dd") // returns "d\u0301\u031dcba"
การใช้งานเหล่านี้สนับสนุนการเรียงลำดับที่ถูกต้องของหลายไบต์ยูนิโคดและการรวมอักขระเมื่อย้อนกลับ
หมายเหตุ: ฟังก์ชันย้อนกลับสตริงในตัวในภาษาการเขียนโปรแกรมหลายภาษาไม่เก็บการรวมไว้และการระบุอักขระที่รวมต้องใช้เวลาดำเนินการมากขึ้นอย่างมาก
แน่นอนว่าไม่ใช่โซลูชันที่มีประสิทธิภาพหน่วยความจำมากที่สุด แต่สำหรับโซลูชันที่ปลอดภัยแบบ UTF-8 แบบ "ธรรมดา" สิ่งต่อไปนี้จะทำให้งานสำเร็จและไม่ทำลายรูน
ในความคิดของฉันอ่านได้และเข้าใจได้มากที่สุดในหน้านี้
func reverseStr(str string) (out string) {
for _, s := range str {
out = string(s) + out
}
return
}
สองวิธีต่อไปนี้ทำงานได้เร็วกว่าวิธีแก้ปัญหาที่เร็วที่สุดที่รักษาการรวมอักขระไว้แม้ว่าจะไม่ได้หมายความว่าฉันขาดบางอย่างในการตั้งค่าเกณฑ์มาตรฐาน
//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
วิธีที่สองได้รับแรงบันดาลใจจากสิ่งนี้
//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
หมายเหตุ:คำตอบนี้มาจากปี 2009 ดังนั้นในตอนนี้อาจมีวิธีแก้ปัญหาที่ดีกว่า
มีลักษณะเป็น 'วงเวียน' เล็กน้อยและอาจไม่มีประสิทธิภาพมากนัก แต่แสดงให้เห็นว่าอินเทอร์เฟซ Reader สามารถใช้อ่านจากสตริงได้อย่างไร IntVectors ดูเหมือนว่าเหมาะมากสำหรับเป็นบัฟเฟอร์เมื่อทำงานกับสตริง utf8
มันจะยิ่งสั้นลงเมื่อละส่วน 'ขนาด' ออกและการแทรกลงในเวกเตอร์โดยการแทรก แต่ฉันเดาว่ามันจะมีประสิทธิภาพน้อยกว่าเนื่องจากเวกเตอร์ทั้งหมดจะต้องถูกผลักกลับทีละครั้งทุกครั้งที่มีการเพิ่มรูนใหม่ .
โซลูชันนี้ใช้ได้กับอักขระ 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());
}
เวอร์ชันที่ฉันคิดว่าใช้ได้กับ Unicode มันถูกสร้างขึ้นบนฟังก์ชัน 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);
}
รูนเป็นประเภทดังนั้นจงใช้มัน ยิ่งไปกว่านั้น Go ไม่ใช้อัฒภาค
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))
}
ลองใช้รหัสด้านล่าง:
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"))
}
สำหรับข้อมูลเพิ่มเติมโปรดตรวจสอบhttp://golangcookbook.com/chapters/strings/reverse/
และhttp://www.dotnetperls.com/reverse-string-go
สำหรับสตริงง่ายๆสามารถใช้โครงสร้างดังกล่าวได้:
func Reverse(str string) string {
if str != "" {
return Reverse(str[1:]) + str[:1]
}
return ""
}
จังหวะง่ายๆด้วยrune
:
func ReverseString(s string) string {
runes := []rune(s)
size := len(runes)
for i := 0; i < size/2; i++ {
runes[size-i-1], runes[i] = runes[i], runes[size-i-1]
}
return string(runes)
}
func main() {
fmt.Println(ReverseString("Abcdefg 汉语 The God"))
}
: doG ehT 语汉 gfedcbA
func Reverse(s string) string {
r := []rune(s)
var output strings.Builder
for i := len(r) - 1; i >= 0; i-- {
output.WriteString(string(r[i]))
}
return output.String()
}
นี่เป็นวิธีแก้ปัญหาอื่น:
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)
}
อย่างไรก็ตามวิธีการแก้ปัญหาของ yazu ข้างต้นมีความสง่างามกว่าเนื่องจากเขาพลิกกลับ[]rune
ชิ้นส่วนเข้าที่
อีกวิธีหนึ่ง (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, "")
}
ทดสอบ
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-string 0.098s
func reverseString(someString string) string {
runeString := []rune(someString)
var reverseString string
for i := len(runeString)-1; i >= 0; i -- {
reverseString += string(runeString[i])
}
return reverseString
}
a+´
á
ฉันสงสัยว่าจะนำมาพิจารณาได้อย่างไรโดยไม่ทำให้เป็นปกติ