如何从字符串中获取单个Unicode字符

40

我想知道如何从字符串中获取Unicode字符。比如,如果字符串是“你好”,那么如何获取第一个字符“你”?

我从另一个地方得到了一种方法:

var str = "你好"
runes := []rune(str)
fmt.Println(string(runes[0]))

它确实有效。 但我还有一些问题:

  1. 是否有其他方法可以做到这一点?

  2. 为什么在Go语言中,str[0]不能从字符串中获取Unicode字符,而是获取了字节数据?

3个回答

44

首先,您可能需要阅读https://blog.golang.org/strings,它将解答您部分问题。

在Go中,字符串可以包含任意字节。当您写下str[i]时,结果是一个字节,索引始终是字节数。

大多数情况下,字符串以UTF-8编码。您可以有多种方法来处理字符串中的UTF-8编码。

例如,您可以使用for...range语句按rune逐个迭代字符串。

var first rune
for _,c := range str {
    first = c
    break
}
// first now contains the first rune of the string

您还可以利用unicode/utf8软件包。例如:

r, size := utf8.DecodeRuneInString(str)
// r contains the first rune of the string
// size is the size of the rune in bytes
如果字符串是用UTF-8编码的,那么没有直接访问字符串中第n个rune的方法,因为rune(以字节为单位)的大小不是固定的。如果您需要此功能,可以轻松编写自己的辅助函数来实现它(使用for...range或unicode/utf8包)。

感谢您的帮助。第二种方法只能获得第一个Unicode字符,似乎不太完美。我理解了第一种方法,并且认为我可以修改它来解决我的问题。我仍然想知道是否有更简单的方法从字符串中按索引获取Unicode字符。 - 赵浩翔
1
正确,但我怀疑在大多数情况下它并不是任何性能瓶颈,当你实际分析了代码并认为有必要进行优化时,优化将变得容易。当然,也有一些情况显然是错误的做法。 - LemurFromTheId
所以,对于给定的 Go 语言字符串,我认为没有直接通过索引检索符文的方法(我的意思是在 O(1) 时间内),但我们必须使用 for range 或首先将其转换为 []rune,这两种方法都需要 O(n) 的时间。这正确吗? - ibic
2
如果您的程序需要多次索引字符串中的符文,请建议在O(n)时间内将其转换为[]rune,然后您可以在O(1)时间内进行任意次数的索引。很可能涉及到的字符串在某个时刻会执行至少一个O(n)操作(即使只是初始赋值),因此添加另一个操作可能不会影响程序的总体渐近运行时间。 - Jason Carlson

2
您可以使用 utf8string 包:
package main
import "golang.org/x/exp/utf8string"

func main() {
   s := utf8string.NewString("ÄÅàâäåçèéêëìîïü")
   // example 1
   r := s.At(1)
   println(r == 'Å')
   // example 2
   t := s.Slice(1, 3)
   println(t == "Åà")
}

https://pkg.go.dev/golang.org/x/exp/utf8string


-2

你可以这样做:

func main() {
  str := "cat"
  var s rune
  for i, c := range str {
    if i == 2 {
      s = c
    }
  }
}

s现在等于a


1
你可能错了一位,因为它是从0开始计数,所以 i == 1 会得到 "a" 吗? - John Gibb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接