go - rune类型
创始人
2024-01-21 09:09:09
0

一、简介

rune类型是Go语言的一种特殊数字类型。
rune是类型int32的别名,在所有方面都等急啊于它,用来区分字符值跟整数值。
Go语言通过rune处理中文,支持国际化多语言。

字符串由字符组成,字符的底层由字节组成,而一个字符串在底层的表示是一个字节序列。
在 Go 语言中,字符可以被分成两种类型处理:
对占 1 个字节的英文类字符,可以使用byte(或者unit8);
对占 1 ~ 4 个字节的其他字符,可以使用rune(或者int32),如中文、特殊符号等。

二、适用场景

2.1 统计带中文字符串长度

	// 使用内置函数 len() 统计字符串长度fmt.Println(len("Go语言编程"))  // 输出:14

在上面示例中,英文字符占用 1 字节,中文字符占用 3 字节,所以得到的长度 14 显然是底层占用字节长度,而不是字符串长度,这时,便需要用到rune类型。

	// 转换成 rune 数组后统计字符串长度fmt.Println(len([]rune("Go语言编程")))  // 输出:6

更标准的用法:

	// 统计字符串长度fmt.Println(utf8.RuneCountInString("Go语言编程")) // 输出:6

2.2 截取带中文字符串

通常情况下,我们会这么做:

	s := "Go语言编程"// 8=2*1+2*3fmt.Println(s[0:8])  // 输出:Go语言

但按照字节的方式进行截取,必须预先计算出需要截取字符串的字节数,如果字节数计算错误,就会显示乱码,比如这样:

	s := "Go语言编程"fmt.Println(s[0:7]) // 输出:Go语�

此外,如果截取的字符串较长,那通过字节的方式进行截取显然不是一个高效准确的办法。那有没有不用计算字节数,简单又不会出现乱码的方法呢?不妨试试这样:

	s := "Go语言编程"// 转成 rune 数组,需要几个字符,取几个字符fmt.Println(string([]rune(s)[:4])) // 输出:Go语言

三、剖析

Go 语言把字符分byte和rune两种类型处理。
byte是类型unit8的别名,用于存放占 1 字节的 ASCII 字符,如英文字符,返回的是字符原始字节。
rune是类型int32的别名,用于存放多字节字符,如占 3 字节的中文字符,返回的是字符 Unicode 码点值。
如下图所示:

	s := "Go语言编程"// bytefmt.Println([]byte(s)) // 输出:[71 111 232 175 173 232 168 128 231 188 150 231 168 139]// runefmt.Println([]rune(s)) // 输出:[71 111 35821 35328 32534 31243]

对应关系如下图:

3.1 RunCountInString方法源码解析

// RuneCountInString is like RuneCount but its input is a string.
func RuneCountInString(s string) (n int) {// 调用 len() 函数得到字节数ns := len(s)for i := 0; i < ns; n++ {c := s[i]// 如码点值小于 128,则为占 1 字节的 ASCII 字符(或者说英文字符),长度 + 1if c < RuneSelf { // RuneSelf = 128// ASCII fast pathi++continue}// 查询首字节信息表,得到中文占 3 字节,所以这里的 x = 3x := first[c]// 判断 x = 3,xx = 241(0xF1)if x == xx {i++ // invalid.continue}// 提取有效的 UTF-8 字节长度编码信息,size = 3size := int(x & 7)if i+size > ns {i++ // Short or invalid.continue}// 提取有效字节范围accept := acceptRanges[x>>4]// accept.lo,accept.hi,表示 UTF-8 中第二字节的有效范围// locb = 0b10000000,表示 UTF-8 编码非首字节的数值下限// hicb = 0b10111111,表示 UTF-8 编码非首字节的数值上限if c := s[i+1]; c < accept.lo || accept.hi < c {size = 1} else if size == 2 {} else if c := s[i+2]; c < locb || hicb < c {size = 1} else if size == 3 {} else if c := s[i+3]; c < locb || hicb < c {size = 1}i += size}return n
}

调用该函数时,传入一个原始的字符串,代码会根据每个字符的码点大小判断是否为 ASCII 字符,如果是,则算做 1 位;如果不是,则查询首字节表,明确字符占用的字节数,验证有效性后再进行计数。

四、参考

[1]. 解析Go中的rune类型

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...