如何在Go中反转字符串?

use*_*499 92 string reverse go

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

yaz*_*azu 85

在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)
}
Run Code Online (Sandbox Code Playgroud)

  • @AnveshChecka,这是不正确的.请参阅http://golang.org/pkg/builtin/#len - 片上的len()肯定会返回元素数,而不是字节数.一片符文是正确的方法. (10认同)
  • 你不能在Go中使用len()来找出字符串/数组/切片等的长度......这是为什么? - Go中的len()表示输入的大小(以字节为单位).它与其长度不符. - 并非所有utf8的符文大小都相同.它可以是1,2,4或8. - 你应该使用unicode/ut8包的方法RuneCountInString来获得符文的长度. (4认同)
  • 这是否适用于组合字符? (3认同)
  • @рытфолд这不适合组合字符.请参阅http://play.golang.org/p/sBgZAV7gCb,组合字符不与其基础交换. (2认同)
  • @Zoidberg:正如你猜测的那样,它不适用于组合字符.例如s:="Les Mise\u0301rables"或s ="noël" (2认同)

小智 51

Russ Cox在golang-nuts邮件列表中表示

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)
}
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢他们如何强迫你考虑编码. (18认同)
  • 偏离主题:为什么它[golang-nuts]而不是[go-nuts]? (7认同)
  • 我不明白为什么这个转换为符文,为什么不``rune:= []符文(输入)`? (4认同)
  • 哇,wtf在倒车的时候用双重赋值?有趣.现在,想想一个符文数量不均匀的字符串.中间的一个得到特殊的治疗,毕竟有正确的最终结果.:)一个有趣的小优化,我不会马上想到的. (2认同)
  • @N4v:使用此解决方案,“rune”被初始化为“len(input)”,它是输入中的字节数。但在 UTF-8 中,符文可以是 1、2、4 或 8 个字节。因此,如果所有符文都是 1 字节 (ASCII) UTF-8 字符,则“input”中的符文数量将等于字节数。但如果某些字符是较长的字节序列,那么符文的数量将小于字节的数量。`rune = rune[0:n]` 从切片末尾修剪掉多余的 0 值符文,然后将其包含在反向循环中并最终出现在 `output` 字符串的前面。 (2认同)

小智 24

这是有效的,没有任何关于功能的问题:

func Reverse(s string) (result string) {
  for _,v := range s {
    result = string(v) + result
  }
  return 
}
Run Code Online (Sandbox Code Playgroud)

  • 虽然它有效,但由于字符串是不可变的,因此效率非常低.我发布了一个更有效的解决方案. (4认同)
  • 这太容易理解了.让它变得更难:-)(并且,"加一"就可以了解它) (4认同)
  • @StanR。符文不是字形。一个字形可以由多个代码点/符文组成。请参阅 http://reedbeta.com/blog/programmers-intro-to-unicode/#combining-marks 反转代码点会将组合标记附加到不同的基本代码点。 (3认同)
  • 这是最好的答案,除非反转字符串是你的瓶颈。 (2认同)
  • 又一个错误的“解决方案”无法正确处理组合字符。 (2认同)

Ran*_*ku' 14

这可以通过考虑两件事来解决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);
}
Run Code Online (Sandbox Code Playgroud)

  • @Software_Monkey:在Go中不允许使用o [i--] = c. - 和++是语句,而不是表达式._表示丢弃(忽略)该变量. (6认同)
  • 在 go 1.1+ 中,它在 string([]int) 行中返回错误,如果将 []rune 类型用于 o,则一切正常 (3认同)
  • @yuku:在 s 上仍然失败 := "Les Mise\u0301rables" (2认同)

Iva*_*hau 13

来自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)
}
Run Code Online (Sandbox Code Playgroud)

去游乐场换一个字符串

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


要保留Unicode组合字符,例如"as⃝df̅"和反向结果"f̅ds⃝a",
请参阅下面列出的其他代码:

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

  • 感谢您澄清与http://stackoverflow.com/a/10030772/3093387的区别 - 似乎这两种解决方案在处理字符串方面有所不同,例如"bròwn". (2认同)
  • 感谢您提到处理组合字符的 Rosettacode 解决方案 (2认同)

pet*_*rSO 10

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 ?")))
}
Run Code Online (Sandbox Code Playgroud)

  • @Tommy:不,`return string(runes)`不适用于所有情况. (3认同)

Eri*_*ric 9

简单的一笔rune

\n
func ReverseString(s string) string {\n    runes := []rune(s)\n    size := len(runes)\n    for i, j := 0, size-1; i < size>>1; i, j = i+1, j-1 {\n        runes[i], runes[j] = runes[j], runes[i]\n    }\n    return string(runes)\n}\n\nfunc main() {\n    fmt.Println(ReverseString("Abcdefg \xe6\xb1\x89\xe8\xaf\xad The God"))\n}\n
Run Code Online (Sandbox Code Playgroud)\n
: doG ehT \xe8\xaf\xad\xe6\xb1\x89 gfedcbA\n
Run Code Online (Sandbox Code Playgroud)\n


Sal*_*ali 8

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

因此,我仔细研究了答案,扔掉了不适用于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
Run Code Online (Sandbox Code Playgroud)

所以这是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)
}
Run Code Online (Sandbox Code Playgroud)

由于某种原因,我无法添加基准,因此可以从中复制基准PlayGround(您无法在其中运行测试)。重命名并运行go test -bench=.

  • 这些“解决方案”都不能正确处理[组合标记](http://reedbeta.com/blog/programmers-intro-to-unicode/#combining-marks)。 (2认同)

Vla*_*den 8

//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
Run Code Online (Sandbox Code Playgroud)

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


Vla*_*uer 6

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

func reverse(s string) (ret string) {
    for _, v := range s {
        defer func(r rune) { ret += string(r) }(v)
    }
    return
}
Run Code Online (Sandbox Code Playgroud)

  • 缓慢并且不能正确处理组合字符。 (2认同)

小智 6

func ReverseString(str string) string {\n  output :=""\n  for _, char := range str {\n    output = string(char) + output\n  }\n  return output\n}\n\n// "Luizpa" -> "apziuL"\n// "123\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" -> "\xe8\xaa\x9e\xe6\x9c\xac\xe6\x97\xa5321"\n// "\xe2\x9a\xbd" -> "\xe2\x9a\xbd"\n// "\xc2\xb4a\xc2\xb4b\xc2\xb4c\xc2\xb4" -> "\xc2\xb4c\xc2\xb4b\xc2\xb4a\xc2\xb4"\n
Run Code Online (Sandbox Code Playgroud)\n


Rae*_*ali 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)
}
Run Code Online (Sandbox Code Playgroud)

我尽力使其尽可能高效和可读.这个想法很简单,遍历符文寻找组合字符,然后将组合字符的符文反转到原位.一旦我们完全覆盖了它们,就可以在适当的位置反转整个字符串的符文.

假设我们想要反转这个字符串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")
}
Run Code Online (Sandbox Code Playgroud)

  • 到目前为止,这是唯一适用于包含字素聚集字符(组合字符)的字符串的答案,例如“2️⃣”,它反转为“2️⃣”。大多数其他答案都返回`⃣️2`。https://paiza.io/projects/K8_kOmxn-cGRR3ksh1vFtw (3认同)

Jon*_*ght 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);
}
Run Code Online (Sandbox Code Playgroud)