如何在Go中反转字符串?

string go reverse

49895 观看

26回复

449 作者的声誉

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

作者: user211499 的来源 发布者: 2009 年 11 月 17 日

回应 (26)


3

67486 作者的声誉

基于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 );
}
作者: martin clayton 发布者: 17.11.2009 11:26

1

10286 作者的声誉

我认为可以在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);
}
作者: Jonathan Wright 发布者: 18.11.2009 04:11

50

0 作者的声誉

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)
}
作者: user181548 发布者: 18.11.2009 07:29

2

444 作者的声誉

看起来有点'回旋',可能效率不高,但说明了如何使用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());
}
作者: Oliver Mason 发布者: 18.11.2009 12:40

15

40308 作者的声誉

这可以通过考虑两件事来解决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);
}
作者: Randy Sugianto 'Yuku' 发布者: 18.11.2009 06:33

22

237 作者的声誉

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

func Reverse(s string) (result string) {
  for _,v := range s {
    result = string(v) + result
  }
  return 
}
作者: Simon 发布者: 11.02.2011 04:07

11

106552 作者的声誉

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 犬")))
}
作者: peterSO 发布者: 11.02.2011 07:14

77

3362 作者的声誉

在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)
}
作者: yazu 发布者: 05.04.2012 02:43

1

753 作者的声誉

符文是一种类型,所以使用它。此外,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))
}
作者: Walter 发布者: 06.04.2012 11:51

3

7031 作者的声誉

这是最快的实现

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)
    }
}
作者: rmuller 发布者: 26.11.2013 06:56

0

11509 作者的声誉

这是另一个解决方案:

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切片的位置。

作者: Jabba 发布者: 29.01.2014 03:13

0

66013 作者的声誉

又一个解决方案(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)
}
作者: OneOfOne 发布者: 29.03.2014 05:36

3

3902 作者的声誉

如果需要处理字形集群,请使用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
}
作者: masakielastic 发布者: 03.11.2014 01:13

1

3604 作者的声誉

此代码保留了完整组合字符的序列,并且也应该使用无效的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

作者: rog 发布者: 03.11.2014 03:20

13

1234 作者的声誉

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

去游乐场换一个字符串

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


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

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

作者: Ivan Chau 发布者: 22.06.2015 07:14

0

452 作者的声誉

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
作者: Alessandro Resta 发布者: 12.12.2015 01:19

6

127699 作者的声誉

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

所以我仔细检查了答案,抛弃了那个对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=.

作者: Salvador Dali 发布者: 30.12.2015 12:17

2

1496 作者的声誉

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

在我看来,这是页面上最易读和易懂的。

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

    return
}
作者: donatJ 发布者: 03.06.2016 08:03

3

339 作者的声誉

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

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

积分

作者: Vladimir Bauer 发布者: 24.06.2016 03:43

1

1600 作者的声誉

尝试以下代码:

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

作者: Vishal Solanki 发布者: 29.06.2016 02:33

1

1434 作者的声誉

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

//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
作者: Sridhar 发布者: 03.09.2016 04:02

5

465 作者的声誉

我写了以下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")
}
作者: Raed Shomali 发布者: 04.06.2017 03:05

2

1331 作者的声誉

您还可以导入现有实现:

import "4d63.com/strrev"

然后:

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

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

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

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

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

作者: Leigh McCulloch 发布者: 24.10.2017 06:28

1

19 作者的声誉

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

func Reverse(str string) string {
    if str != "" {
        return Reverse(str[1:]) + str[:1]
    }
    return ""   
}
作者: Sergo Kurbanov 发布者: 17.01.2018 10:36

0

21 作者的声誉

    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
    }
作者: saurabh 发布者: 31.08.2018 05:33

0

35636 作者的声誉

//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倍

作者: Vlad Bezden 发布者: 25.08.2019 10:57
32x32