Go 中的 byte、rune 与 string

byte 和 rune

byte 是 uint8 的别名,其字面量是 8 位整数值,byte 切片相比于不可变的 string 方便常用许多。它可以更改每个字节或字符。这对于处理文件内容(无论是文本文件、二进制文件还是来自网络的I/O流)非常有效。byte 切片是一个可变的字节序列

rune 是 int32 的别名,其字面量是 32 位整数值,用来表示 Unicode 字符编码。rune 类似于 byte,不同点在于 rune 每个索引是一个字符而不是一个字节。rune 切片是对字节片的重新分组使得每个索引都是一个字符。

如果你处理的文本文件有很多非 ascii 字符,比如中文文本、数学公式或带有表情符号的文本,使用 rune 是最好的。

rune 也是从字符串中获取子字符串的理想选择。它支持 Unicode 字符,没有数据损坏的风险。

对于 []rune,len()和索引都是基于 rune(int32)的。
当你将 []rune 转换为 string 时,每个 rune 成为字符串中的一个 utf-8 字符。

byte 和 rune 的区别

func main() {
	s := "G?"
	sample := "H哈"

	sByte := []byte(s)
	sRune := []rune(s)
	sampleByte := []byte(sample)
	sampleRune := []rune(sample)

	fmt.Printf("%s\nsByte: %d\nsRune: %d\n", s, sByte, sRune)
	fmt.Println("------")
	fmt.Printf("%s\nsampleByte: %d\nsampleRune: %d\n", sample, sampleByte, sampleRune)
}

可以看到rune 中非 ASCII 码字符的 Unicode 编码为 1-3 字节,与 ASCII 码字符的字节数不一定相同。

string

string 是不可变的 byte 切片。因为Go中的源代码使用 utf-8 编码,因此每个字符串也使用utf-8编码,即 string 字面量是 utf-8 编码,以 byte 为单位的。string 中的每个字符实际占用 1-3 个字节,而每个 rune 占 4 个字节。

  • 使用 rune() 可把 byte 为单位的字符转换为 rune 字符,对于 ASCII 字符来说,rune 值和 byte 值相同,而对于 Unicode 编码的字符来说便不同了。
  • 使用 []rune() 将 string 转换 rune 数组。当将字符串转换为 rune 切片时,字符串中的每个 utf-8 字符被转换为一个 rune,从而获得包含字符串 Unicode 编码字符的新切片。
  • 对于 string,len()和索引都是基于 byte(unint8)的
  • 在 Go 中将字符串转换为 rune 切片是一个标准操作,没有数据损坏的风险。
    字符串是处理短字节或字符序列比较好的方法。每次对字符串进行操作(例如查找替换字符串或接受子字符串)时,都会创建一个新的字符串。如果字符串非常大,例如文件内容,则效率非常低。

string 中索引字符

例如我们先看下面程序:

func main() {

	sample := "Hel哈"
	for i := 0; i < len(sample); i++ {
		fmt.Print(sample[i], " ")
	}
	fmt.Println()
	fmt.Printf("%s\t的字节长度: %d\n", sample, len(sample))
	fmt.Printf("哈\t字符的字节长度: %d\n", utf8.RuneLen(‘哈‘))
	fmt.Printf("%s\t的字符长度: %d\n", sample, utf8.RuneCountInString(sample))
}

输出:

72 101 108 229 147 136 
Hel哈   的字节长度: 6
哈      字符的字节长度: 3
Hel哈   的字符长度: 4

可以看出字符串的长度(len)和字符串的字符长度(RuneCountInString)是不同的。因为字符串是字节切片,Go 默认 UTF-8,存储非 ASCII 字符时,每个字符则会存储 1-3 个字节。所以想要正确地索引字符串中的字符有以下两种方法:

  1. 将字符串转换为 rune 切片
  2. 使用 range 操作符迭代 Unicode 字符
    也就是说对字符串进行 rang 迭代,是字符迭代,而不是字节迭代。

关于编码的一些方法

utf8.ValidRune(chr) 判断 chr 是否可以编码为合法的utf-8序列。
utf8.RuneLen(chr) 查看字符 chr 的字节长度
utf8.RuneCount() 查看字节数组中按照 rune 单位的字符长度
utf8.RuneCountInString 查看字符串按照 rune 单位的长度

参考资料

  1. Golang: How To Convert String To Rune in Go Example
  2. go - What is a rune? - Stack Overflow

Go 中的 byte、rune 与 string

上一篇:短信宝发送短信


下一篇:sublime多行同时编辑