我们如何在Go中反转一个简单的字符串?
答案 0 :(得分:74)
在Go1符文中是内置类型。
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)
}
答案 1 :(得分:47)
Russ Cox, on the golang-nuts mailing list,建议
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)
}
答案 2 :(得分:22)
这很有效,但没有任何关于功能的问题:
func Reverse(s string) (result string) {
for _,v := range s {
result = string(v) + result
}
return
}
答案 3 :(得分:15)
这可以通过考虑两件事来解决unicode字符串:
所以这就是:
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);
}
答案 4 :(得分:11)
当Simon发布his solution时,我注意到了这个问题,因为字符串是不可变的,效率非常低。其他提议的解决方案也存在缺陷;他们不工作或效率低下。
这是一个有效的解决方案,除非字符串无效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 犬")))
}
答案 5 :(得分:11)
来自Go example projects: 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)
}
Go Playground for reverse a string
反转字符串“bròwn”后,正确的结果应该是“nwòrb”,而不是“nẁorb”。
注意字母o上面的坟墓。
用于保存Unicode组合字符,例如“as⃝df̅”,反向结果为“f̅ds⃝a”,
请参阅下面列出的其他代码:
答案 6 :(得分:5)
我编写了以下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
,另一个用于此unicode \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")
}
答案 7 :(得分:4)
这里答案太多了。其中一些是明确的重复。但即使是从左边开始,也难以选择最佳解决方案。
所以我仔细检查了答案,扔掉了那个对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
所以这是fastest method by 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=.
答案 8 :(得分: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, "" );
}
替代,不使用字符串包,但不使用'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 );
}
答案 9 :(得分:3)
如果您需要处理字形集群,请使用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
}
答案 10 :(得分: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)
}
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)
}
}
答案 11 :(得分:2)
这是完全不同的,我会说更多的功能方法,没有列在其他答案中:
func reverse(s string) (ret string) {
for _, v := range s {
defer func(r rune) { ret += string(r) }(v)
}
return
}
答案 12 :(得分:2)
毫无疑问,这不是最节省内存的解决方案,但对于“简单”的UTF-8安全解决方案,以下内容将完成工作而不会破坏符文。
在我看来,这是页面上最具可读性和可理解性的。
func reverseStr(str string) (out string) {
for _, s := range str {
out = string(s) + out
}
return
}
答案 13 :(得分:2)
您还可以导入现有的实施:
strrev.Reverse("abåd") // returns "dåba"
然后:
strrev.ReverseCombining("abc\u0301\u031dd") // returns "d\u0301\u031dcba"
或者反转包含unicode组合字符的字符串:
# If your input value is only a number then use "Value.isdigit() == False".
# If you need an input that is a text, you should remove "Value.isdigit() == False".
def Input(Message):
Value = None
while Value == None or Value.isdigit() == False:
try:
Value = str(input(Message)).strip()
except InputError:
Value = None
return Value
# Example:
age = 0
# If we suppose that our age is between 1 and 150 then input value accepted,
# else it's a wrong value.
while age <=0 or age >150:
age = int(Input("Please enter your age: "))
# For terminating program, the user can use 0 key and enter it as an a value.
if age == 0:
print("Terminating ...")
exit(0)
if age >= 18 and age <=150:
print("You are able to vote in the United States!")
else:
print("You are not able to vote in the United States.")
这些实现支持unicode多字节的正确排序,并在反转时梳理字符。
注意:许多编程语言中的内置字符串反转函数不保留组合,识别组合字符需要更多的执行时间。
答案 14 :(得分:2)
看起来有点'迂回',可能效率不高,但说明了如何使用Reader接口读取字符串。在使用utf8字符串时,IntVectors似乎也非常适合作为缓冲区。
当省略'size'部分并通过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);
}
return string(output.Data());
}
答案 15 :(得分:1)
我认为可以在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);
}
答案 16 :(得分:1)
以下两种方法的运行速度比最快solution that preserve combining characters快,但这并不是说我在基准设置中遗漏了一些东西。
//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
受this
启发的第二种方法//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
答案 17 :(得分:1)
对于简单的字符串,可以使用这种结构:
func Reverse(str string) string {
if str != "" {
return Reverse(str[1:]) + str[:1]
}
return ""
}
答案 18 :(得分:1)
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()
}
答案 19 :(得分:1)
func ReverseString(str string) string {
output :=""
for _, char := range str {
output = string(char) + output
}
return output
}
// "Luizpa" -> "apziuL"
// "123日本語" -> "語本日321"
// "⚽?" -> "?⚽"
// "´a´b´c´" -> "´c´b´a´"
答案 20 :(得分:1)
尝试以下代码:
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
答案 21 :(得分:1)
此代码保留完整组合字符的序列,和 也应该使用无效的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)
}
如果unicode / norm原语可能会更高效 允许在没有的情况下迭代字符串的边界 分配。另请参阅https://code.google.com/p/go/issues/detail?id=9055。
答案 22 :(得分:1)
符文是一种类型,所以使用它。此外,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))
}
答案 23 :(得分:0)
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
答案 24 :(得分:0)
又一个解决方案(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)
}
答案 25 :(得分:0)
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
}
答案 26 :(得分:0)
使用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
答案 27 :(得分:0)
这是另一种解决方案:
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
切片。
答案 28 :(得分:0)
func reverseStr(b string) {
for _, v := range []rune(b) {
defer fmt.Printf("%c", v)
}
}
Defer 对此很有用,因为它是 LIFO - 后进先出
答案 29 :(得分:-1)
//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比使用字符串连接快约三倍