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

  • 据我所知,下面给出的解决方案不适用于预先组合或组合字符,例如给出a+而不是。 我想知道如何在没有规范化的情况下考虑到这一点。
  • 如果您对大量类似答案感到困惑,请查看我的基准。

在Go1中,符文是内置类型。

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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)
}
  • 我喜欢他们如何强迫你考虑编码。
  • 偏离主题:为什么它[golang-nuts]而不是[go-nuts]?
  • 哇,wtf在倒车的时候用双重赋值?有趣。现在,想想一个符文数量不均匀的字符串。中间的一个得到特殊的治疗,毕竟有正确的最终结果。 :)一个有趣的小优化,我不会马上想到的。
  • 我不明白为什么这个转换为符文,为什么不rune:=[]rune(input)
  • 你不需要第一个用于范围循环。输出:= []符文(输入); n:= len(输出)你不需要符文=符文[0:n]
  • 我同意@dvallejo,请参阅play.golang.org/p/S2NIvT_DJ6第一个循环没用,并且没有理由构建符文=符文[0:n]
  • 还有一个错误的"解决方案",它不能正确地组合字符。
  • 不能合并角色,例如:"快速兄弟狐狸跳过懒惰的犬"
  • @dolmen:点了点,但值得赞扬的是,Russ在邮件列表帖子中指出,他的解决方案忽略了组合字符。
  • 是什么意思将rune设置为此行中的一部分:rune = rune[0:n]。看起来这是多余的。
  • @ N4v:使用此解决方案,rune初始化为len(input),这是输入中的字节数。但是符文在UTF-8中可以是1,2,4或8个字节。因此,如果所有符文都是1字节(ASCII)UTF-8字符,则input中的符文数将等于字节数。但是如果某些字符是较长的字节序列,那么符文的数量将小于字节数。 rune = rune[0:n]从切片的末尾修剪多余的0值符文,然后将其包含在反向循环中并在output字符串的前面结束。

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

1
2
3
4
5
6
func Reverse(s string) (result string) {
  for _,v := range s {
    result = string(v) + result
  }
  return
}
  • 虽然它有效,但由于字符串是不可变的,因此效率非常低。我发布了一个更有效的解决方案。
  • 这太容易理解了。让它变得更难:-)(并且,"加一"就可以了解它)
  • 这是最好的答案,除非逆转字符串是你的瓶颈。
  • 还有一个错误的"解决方案",它不能正确地组合字符。
  • @dolmen - 为什么这不会处理组合字符?字符串上的范围返回一个符号的符文。
  • @StanR。符文不是字形。字形可以由多个代码点/符文组成。请参阅reedbeta.com/blog/programmers-intro-to-unicode/#combining-marks反转代码点会将组合标记附加到不同的基本代码点。

这可以通过考虑两件事来解决unicode字符串:

  • range通过枚举unicode字符来处理字符串
  • string可以从int切片构造,其中每个元素都是一个unicode字符。

所以这里:

1
2
3
4
5
6
7
8
9
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折叠成一行for _, c:=range s { o[i--]=c; }。男人我讨厌没有括号的for - 这是允许的:for(_, c:=range s) { o[i--]=c; }
  • 你能解释_的作用吗?
  • @Software_Monkey:在Go中不允许使用o [i--] = c。 - 和++是语句,而不是表达式。 _表示丢弃(忽略)该变量。
  • 使用go 1.1+它会返回string([] int)行中的错误,如果改为[]符文类型用于o,则所有工作
  • @yuku:仍在s:="Les Mise u0301"

来自Go示例项目:golang / example / stringutil / reverse.go,作者是Andrew Gerrand

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
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

  • 感谢您澄清stackoverflow.com/a/10030772/3093387的不同之处 - 似乎这两种解决方案在处理字符串如"brwn"方面有所不同。
  • 感谢您提及处理组合字符的Rosettacode解决方案

当Simon发布他的解决方案时,我注意到了这个问题,因为字符串是不可变的,效率非常低。其他提议的解决方案也存在缺陷;他们不工作或效率低下。

这是一个有效的解决方案,除非字符串无效UTF-8或字符串包含组合字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 犬")))
}
  • 返回字符串(符文)也适用。
  • @Tommy:不,return string(runes)不适用于所有情况。
  • 你能解释一下为什么会这样吗?我做了一个简短的程序,它在那里工作,但也许你谈到的那些情况不会在那里触发? play.golang.org/p/yk1sAwFjol
  • @Tommy:您的简短程序仅表明NUL字符在发送到打印机或终端时是NOP。您的Reverse2函数对于非ASCII UTF-8编码的字符串失败。我修改了你的短程序,以便进行有效的测试:play.golang.org/p/Ic5G5QEO93
  • 还有一个错误的"解决方案",它不能正确地组合字符。

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

所以我仔细检查了答案,抛弃了那个对unicode不起作用的答案,并删除了重复项。我对幸存者进行了基准测试,以找到最快的。以下是归因结果(如果您注意到我错过的答案,但值得添加,请随意修改基准):

1
2
3
4
5
6
7
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最快的方法:

1
2
3
4
5
6
7
8
9
10
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编码和组合字符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 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找到它。

以下是一些测试用例,展示了几种不同的场景:

1
2
3
4
5
6
7
8
9
10
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")
}

基于Stephan202的原始建议,似乎适用于unicode字符串:

1
2
3
4
5
6
7
8
9
10
11
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':

1
2
3
4
5
6
7
8
9
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 );
}
  • +1。这样可行。但我必须说,对于这样一个简单的任务来说,分裂和加入是相当奇怪的(现在)...
  • @martin:对不起那个编辑。我不小心在你的问题中贴了我更新的答案......我很惭愧。
  • 我试图回滚。希望我做对了。
  • @Stephan - 没问题。我添加了一个替代解决方案,基于字符串包Bytes函数。
  • @Nosradena:我在同一分钟内回滚(我很惊讶地看到Martin用我刚刚写的完全相同的文字更新了他的答案......然后我突然明白了;)
  • @Nosredna - 看起来我认为 - 谢谢。
  • @martin:如果你问我,第二个版本看起来更好:)
  • 还有一个错误的"解决方案",它不能正确地组合字符。

此代码保留了完整组合字符的序列,以及
也应该使用无效的UTF-8输入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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。

  • 字符串值中没有这种"无效的UTF-8输入":当从[]byte转换为string时,Go用有效的代码点\uFFFD替换"无效的UTF-8输入"。
  • 我不明白上面的评论。您是否说当使用包含无效UTF-8的字符串时,此代码的行为是错误的?
  • 不,我说Go string中的无效UTF-8不存在。但它可以存在于[]byte中。
  • Go字符串可以包含与[]字节一样多的无效utf-8。例如:play.golang.org/p/PG0I4FJfEN
  • 好。我上面的所有陈述都是错误的。

这是最快的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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)
    }
}
  • 在声称最快的实施之前,您是否对解决方案进行了基准测试
  • 是的,我做了,这就是为什么BenchmarkReverse代码存在:)。但是我不再有结果了。
  • 快速解决方案,但仍然错误,因为它没有正确组合字符。
  • 这是真的,因为@dolmen说这不会处理组合字符?这有解决方案吗?

如果需要处理字形集群,请使用unicode或regexp模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
}
  • 我想给你1000个赞成票。此页面上的所有其他实现都错误地反转了STRING(STRING不是一系列字符)。
  • 这不起作用。如果双击字符串,则不会获得原始字符串。领先的Combining Diaeresis( u0308),在此示例中使用,与前面的字符组合,在反转时创建双重变音符a。如果输出str,则修改前导引号!

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

1
2
3
4
5
6
func reverse(s string) (ret string) {
    for _, v := range s {
        defer func(r rune) { ret += string(r) }(v)
    }
    return
}

积分

  • 我很确定它不是最快的解决方案,但它显示了返回变量ret如何通过每个延迟函数保持关闭以进行进一步处理。
  • 慢,并没有正确组合字符。
  • 我不确定它有多快,但它的美丽。

您还可以导入现有实现:

1
import"4d63.com/strrev"

然后:

1
strrev.Reverse("ab?d") // returns"d?ba"

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

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

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

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


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

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

1
2
3
4
5
6
7
func reverseStr(str string) (out string) {
    for _, s := range str {
        out = string(s) + out
    }

    return
}

符文是一种类型,所以使用它。此外,Go不使用分号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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]
", str, reverse(str))
}
  • 发布该问题时,它使用分号。
  • 还有一个错误的"解决方案",它不能正确地组合字符。

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

1
2
3
4
5
6
7
8
//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

第二种方法受此启发

1
2
3
4
5
6
7
8
9
10
11
//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接口读取字符串。在使用utf8字符串时,IntVectors似乎也非常适合作为缓冲区。

在省略'size'部分并通过Insert插入向量时会更短,但我想这样效率会降低,因为每次添加新符文时需要将整个向量推回一个。

这个解决方案肯定适用于utf8字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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());
}
  • 为什么要添加所有那些尾随的分号?
  • 因为我学习了编写C和Java的编程;)
  • @ olivier-mason分享Go代码时,了解gofmt的时间。
  • 答案来自八年前。
  • @OliverMason修复(或删除)不完美的解决方案永远不会太晚。

尝试以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
", reverse("abcdefg"))
}

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

1
2
3
4
5
6
func Reverse(str string) string {
    if str !="" {
        return Reverse(str[1:]) + str[:1]
    }
    return""  
}

我认为可以在unicode上运行的版本。它建立在utf8.Rune函数上:

1
2
3
4
5
6
7
8
9
10
11
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);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//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倍


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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,"")
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package reverseString

import (
   "fmt"
   "strings"
   "testing"
)

func TestReverseString(t *testing.T) {

    s :="GO je ú?asné!"
    r := ReverseString(s)

    fmt.Printf("Input: %s
Output: %s", s, r)

    revR := ReverseString(r)

    if strings.Compare(s, revR) != 0 {
        t.Errorf("Expecting: %s
. Got: %s
", s, revR)
    }
}

产量

1
2
3
4
Input: GO je ú?asné!
Output: !énsa?ú ej OG
PASS
ok      github.com/alesr/reverse-string 0.098s
  • 如果输入是NFC,则此方法有效。但是,正如大多数其他错误的解决方案一样,它不能用于组合字符。

这是另一个解决方案:

1
2
3
4
5
6
7
8
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切片反转到位。


1
2
3
4
5
6
7
8
    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
    }

又一个解决方案(tm):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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)
}