122

我们如何在 Go 中反转一个简单的字符串?

4

33 回答 33

123

在 Go1 中,rune 是一种内置类型。

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)
}
于 2012-04-05T14:43:12.210 回答
59

在 golang-nuts 邮件列表中,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)
}
于 2009-11-18T07:29:26.340 回答
41

这行得通,没有所有关于函数的麻烦:

func Reverse(s string) (result string) {
  for _,v := range s {
    result = string(v) + result
  }
  return 
}
于 2011-02-11T04:07:21.010 回答
20

来自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)
}

Go Playground 用于反转字符串

反转字符串“bròwn”后,正确的结果应该是“nwòrb”,而不是“nẁorb”。
注意字母o上方的坟墓。


为了保留Unicode组合字符,例如“as⃝df̅”和反向结果“f̅ds⃝a”,
请参考下面列出的另一个代码:

http://rosettacode.org/wiki/Reverse_a_string#Go

于 2015-06-22T07:14:24.143 回答
15

通过考虑两件事,这适用于 unicode 字符串:

  • range通过枚举 unicode 字符来处理字符串
  • string 可以从 int 切片构造,其中每个元素都是一个 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);
}
于 2009-11-18T18:33:29.873 回答
14

当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 犬")))
}
于 2011-02-11T07:14:57.687 回答
14

我编写了以下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。Theò由两个符文表示,一个代表 the 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")
}
于 2017-06-04T03:05:40.897 回答
13

这里的答案太多了。其中一些是明显的重复。但即使是从左边,也很难选择最佳解决方案。

因此,我浏览了答案,丢弃了不适用于 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=.

于 2015-12-30T00:17:55.253 回答
9
//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

使用 strings.Builder 比使用字符串连接快大约 3 倍

于 2019-08-25T10:57:30.763 回答
6

这是完全不同的,我会说更多功能的方法,未在其他答案中列出:

func reverse(s string) (ret string) {
    for _, v := range s {
        defer func(r rune) { ret += string(r) }(v)
    }
    return
}
于 2016-06-24T15:43:57.870 回答
4

这是最快的实现

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)
    }
}
于 2013-11-26T18:56:53.497 回答
4

一个简单的笔画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
于 2020-08-31T06:17:50.060 回答
3

您还可以导入现有的实现:

import "4d63.com/strrev"

然后:

strrev.Reverse("abåd") // returns "dåba"

或反转包含 unicode 组合字符的字符串:

strrev.ReverseCombining("abc\u0301\u031dd") // returns "d\u0301\u031dcba"

这些实现支持 unicode 多字节的正确排序和反转时的组合字符。

注意:许多编程语言中的内置字符串反转函数不保留组合,识别组合字符需要更多的执行时间。

于 2017-10-24T06:28:57.743 回答
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)

            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
}
于 2014-11-03T13:13:08.693 回答
2

此代码完整地保留了组合字符的序列,并且也可以处理无效的 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

于 2014-11-03T15:20:06.970 回答
2
func ReverseString(str string) string {
  output :=""
  for _, char := range str {
    output = string(char) + output
  }
  return output
}

// "Luizpa" -> "apziuL"
// "123日本語&quot; -> "語本日321"
// "⚽&quot; -> "⚽&quot;
// "´a´b´c´" -> "´c´b´a´"
于 2021-04-20T01:47:47.943 回答
2

这肯定不是最节省内存的解决方案,但对于“简单”的 UTF-8 安全解决方案,以下将完成工作并且不会破坏符文。

在我看来,它是页面上最易读和最容易理解的。

func reverseStr(str string) (out string) {
    for _, s := range str {
        out = string(s) + out
    }

    return
}
于 2016-06-03T20:03:00.160 回答
1

注意:这个答案来自 2009 年,所以现在可能有更好的解决方案。


看起来有点“迂回”,可能效率不高,但说明了如何使用 Reader 接口读取字符串。在处理 utf8 字符串时,IntVectors 似乎也非常适合作为缓冲区。

省略“大小”部分并通过 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());
}
于 2009-11-18T12:40:57.223 回答
1

对于简单的字符串,可以使用这样的结构:

func Reverse(str string) string {
    if str != "" {
        return Reverse(str[1:]) + str[:1]
    }
    return ""   
}
于 2018-01-17T22:36:20.213 回答
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()
}
于 2020-10-10T20:41:26.947 回答
1

简单、甜美和高性能

func reverseStr(str string) string {
  strSlice := []rune(str)  //converting to slice of runes
  length := len(strSlice)

  for i := 0; i < (length / 2); i++ {
      strSlice[i], strSlice[length-i-1] = strSlice[length-i-1], strSlice[i]
  }
  return string(strSlice)  //converting back to string
}
于 2021-09-03T02:38:12.790 回答
1

以下两种方法比保留组合字符的最快解决方案运行得更快,但这并不是说我在基准设置中遗漏了一些东西。

//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
于 2016-09-03T16:02:32.147 回答
1

逐字反转字符串是一个类似的过程。首先,我们将字符串转换为字符串数组,其中每个条目都是一个单词。接下来,我们将正常的反向循环应用于该数组。最后,我们将结果重新组合成一个字符串,我们可以将其返回给调用者。

package main

import (
    "fmt"
    "strings"
)

func reverse_words(s string) string {
    words := strings.Fields(s)
    for i, j := 0, len(words)-1; i < j; i, j = i+1, j-1 {
        words[i], words[j] = words[j], words[i]
    }
    return strings.Join(words, " ")
}

func main() {
    fmt.Println(reverse_words("one two three"))
}
于 2021-09-21T16:26:19.917 回答
0

我认为适用于 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);
}
于 2009-11-18T04:11:10.270 回答
0

符文是一种类型,所以使用它。此外,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))
}
于 2012-04-06T11:51:09.773 回答
0

字符串在 golang 中是不可变的对象,不像 C 就地反向在 golang 中是不可能的。使用 C ,您可以执行以下操作,

void reverseString(char *str) {
  int length = strlen(str)
  for(int i = 0, j = length-1; i < length/2; i++, j--)
  {
    char tmp = str[i];
    str[i] = str[j];
    str[j] = tmp;
  }
}

但是接下来的golang使用字节将输入转换为字节,然后在反转后将字节数组反转,在返回之前转换回字符串。仅适用于非 unicode 类型的字符串。

package main

import "fmt"

func main() {
    s := "test123 4"
    fmt.Println(reverseString(s))
}

func reverseString(s string) string {
    a := []byte(s)
    for i, j := 0, len(s)-1; i < j; i++ {
        a[i], a[j] = a[j], a[i]
        j--
    }
    return string(a)
}
于 2021-12-10T18:03:08.980 回答
0

试试下面的代码:

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

于 2016-06-29T14:33:17.533 回答
-1

这是另一个解决方案:

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切片反转到位。

于 2014-01-29T15:13:03.080 回答
-1

另一个解决方案(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)
}
于 2014-03-29T17:36:29.010 回答
-1
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, "")
}

Test

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)
    }
}

Output

Input: GO je úžasné!
Output: !énsažú ej OG
PASS
ok      github.com/alesr/reverse-string 0.098s
于 2015-12-12T13:19:08.897 回答
-1

另一个技巧是使用内置的语言功能,例如defer

package main

import "fmt"

func main() {
    var name string
    fmt.Scanln(&name)

    for _, char := range []rune(name) {
        defer fmt.Printf("%c", char) // <-- LIFO does it all for you
    }
}
于 2022-01-20T12:35:09.793 回答
-1
    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
    }
于 2018-08-31T05:33:01.027 回答
-1
func reverseStr(b string) {
for _, v := range []rune(b) {
    defer fmt.Printf("%c", v)

}
 }

Defer 对此很有用,因为它是 LIFO - 后进先出

于 2021-02-17T15:56:20.800 回答