golang – 关于字符编码

不同语言在编码处理的部分各有不同,但是套路基本就2种。

以C/C++为一派,它们因为是编译成机器码的语言,所以在编码处理方面比较原始:

源代码文件是采用什么编码写的,那么字符串就是什么编码,完全可以用GBK编码开发程序。

Java,Python则是另外一派:

源代码文件必须是UTF-8的,解释器会在运行时把源代码中的UTF-8字符转成Unicode存储

Golang呢,其实属于中间状态:

它要求源代码必须是UTF-8,但是编译二进制时仍旧会保持字符串的UTF-8编码。

string一定是utf-8编码

我们在IDE中编写的Go源代码都是UTF-8的,因此下面的string是UTF-8的:

求string的长度实际是字节长度而不是字符个数,因此:

  • len(s)是3
  • s[1]可以取到第1个字节

遍历字符必须用rune

因为UTF-8是变长编码,为了按数组风格访问到每一个字符,就需要先转回Unicode。

在Golang中,Unicode字符的数据类型是rune,它实际是int32类型的别名,为什么unicode字符需要4个字节呢?因为Unicode最新标准是 UCS-4,也就是用4个字节可以表示世界上任意的字符,所以Golang把存储空间是一步做到位了。

在golang中并不需要特殊的编码转换函数,从UTF-8转Unicode是Golang语言级支持的,只需要对string或者[]byte做[]rune转换即可解码为Unicode字符数组。

因此:

  • len(r)输出1
  • r[0]输出20320,也就是”你”的Unicode十进制表示,如果要打印”你”,需要用string(r[0])完成从Unicode到Utf-8的反向编码,这是Golang语言级自动支持的。

range遍历string的特殊性

利用for+range遍历string,得到的并不是字节,而是Unicode字符,也就是逐个的rune。

从UTF-8编码到Unicode的解码过程也是Golang语言级自动支持的:

上述代码将输出20230,如果要打印成可见字符串,还是应该把Unicode编码回Utf-8:

如果你就是想逐个字节的遍历string,那么先把string转成[]byte即可。

向其他编码转换

如果我们想得到GBK编码的”你”,在Golang世界中并不是以Unicode作为基准的,而是以UTF-8编码,这与其他语言的差别是比较大的。

我们需要安装一个Golang标准扩展库:

go get golang.org/x/text/…

其中…的意思是递归引入golang.org/x/text项目下面所有子项目(目录),所谓项目就是有go.mod的目录。

然后,我们只需要这样一个操作,就可以完成从UTF-8编码 -> Unicode编码 -> GBK编码的全过程:

我们只需要传入UTF-8字符串,transform配合GBK的encoder可以完成剩余2步转换。

 

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~