Golang:一文搞懂string,unicode,ut

8a85f1ae88fa37501631c5706b29282b.png

string

要解释rune类型,我们先要了解string类型。
string 类型的本质是一连串8个bit的字节, string 字符串可以直接转换成[]byte类型

s := "abc"
fmt.Println([]byte(s))

// output
// [97 98 99]
复制代码

以上代码打印了字符在ascii 编码表中的编号。
当然,不仅可以打印字符编号,也可以直接打印相应的字符

s := "abc"
for _, v := range []byte(s) {
    fmt.Printf("%c, %v\n", v, v)
}
// output
// a, 97
// b, 98
// c, 99
复制代码

我们可以说, string类型本质上就是一组字节组成的数组([]byte)。

Golang 源码本身使用的是UTF-8编码(非utf-8格式的源码不能编译),除了ascii,golang 也可以打印Unicode的字符编码,

    for _, v := range "汉字" {
        fmt.Printf("character %c,unicode %U \n", v, v)
    }
// output:
// character 汉,unicode U+6C49 
// character 字,unicode U+5B57 
复制代码

Unicode 和 UTF-8

要了解rune,我们还需要了解unicode和utf8

Unicode和 UTF-8的关系:

  • Unicode 是一个编码表,在v13.0版本中,拥有143,859 个字符.
  • UTF-8 是一种对Unicode 的编码方式.
  • UTF-8 对一个字符使用1-4个字节进行编码.

这张图展示了UTF-8的编码规则

image.png

  • Code point(码点),也就是字符在unicode 中对应的编号。

  • 使用一个字节编码的码点范围是0~7F, 对应的十进制就是0-127. 这里完全兼容了ascii编码表.

  • 使用两个字节编码的码点范围是80-7FF, 对应的十进制就是128-2047。这部分主要是一些拉丁文

  • 中文的码点范围是4E00-9FFF, 共计20992个字符,对应着编码规则的第三条,使用3个字节进行编码.

有兴趣的可以看看unicode 编码表unicode-table.com/en/blocks/

rune

了解了string, 以及unicode, utf8编码之后,我们现在可以来讨论什么是rune 类型了, 以及为什么要有rune类型。
先来看一段代码:

chinese := "汉字"
fmt.Printf("length: %d\n", len(chinese))
复制代码

你们觉得结果是什么?
答案居然是6?

length: 6
复制代码

为什么长度是6?

文章开头我们说过,string类型的本质就是[]byte,底层使用byte来表示对应的字符。

len(string) 表示字符串的字节长度

在UTF-8编码规则中,一个中文占3个字节,“汉字” 这两个中文的长度就是6了

那我们该怎么统计正确的中文长度呢?
现在把字符串转换成rune类型试一下

chinese := []rune("汉字")
fmt.Printf("length: %d\n", len(chinese))
// output
// length: 2
复制代码

这次的结果是2,正确的得出了字符的长度。

现在我们知道,rune 的值表示字符的码点,而码点就是unicode 中字符的编码。
将string 转换成rune类型的同时,就是将UTF8编码的字符,变成了一个个码点(code-point)

range string

再来看一下上面那个例子, 这次我们把它的索引打出来.

    for i, v := range "汉字" {
        fmt.Printf("character %c,value %d,unicode %U position %d\n", v, v, v, i)
    }    
// output:
// character 汉,value 27721,unicode U+6C49 position 0
// character 字,value 23383,unicode U+5B57 position 3
复制代码

在对string循环的时候,是比较特别的。因为index并不等于字符在string中的位置,而是对应着字符在string中byte的起始位置.

总结

rune 是golang中的一种数据类型,底层类型是int32,用来存储unicode code-point.

type rune = int32
复制代码

Ref: