< 返回技术文档列表

Golang中Unicode与UTF-8有什么区别

发布时间:2021-09-01 01:08:30⊙投诉举报

Golang中Unicode与UTF-8有什么区别,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

Unicode 与 UTF-8 编码

下面的图来自 UTF-8 的截图:

Golang中Unicode与UTF-8有什么区别

这幅图简单明了的告诉我们,UTF-8 的编码方式,比如汉字一般用三个 Byte,每个 Byte 的开头都是固定的,各种文字软件解析 UTF-8  编码的时候,它就会按照这个格式去解析,一旦解析错误(毕竟还可能会有不符合要求的数据,或者是文件错误了),错误的字节就会被替换为 “�”  (U+FFFD),然后神奇的地方就来了: 即使遇到这种错误,它也不会影响接下来的其他字符的解析 ,因为这种编码不必从头开始,使得它可以  自我同步(Self-synchronizing) 。与此同时,其它的一些编码一旦遇到错误编码就会出问题,导致错误编码之后的正确编码也会跟着出错。

当然,UTF-8 编码也有缺点,由于它是可变的,当英文字符偏多的时候,它会省空间,然而比如当中文偏多的时候,它理论上(3 Byte)会比 GBK 编码(2  Byte)最多多出 1/3 的存储空间。

UTF-8 的例子

我们拿 Unicode 中最受欢迎的 Emoji 表情 :joy: 1 来举例:它的 Code point 是 U+1F602 (对, 1F602 是以  16 进制表示的),然而在内存中它的存储方式的却是 0xf09f9882 ,为什么?这就是 UTF-8 的编码了(注意对比上图的编码方式):

000    011111    011000    000010 1f602 11110000  10011111  10011000  10000010 f0 9f 98 82

通过把 UTF-8 的编码格子里面数据提取出来,我们就能获得 Code point 1F602 。

你也可以用 Golang 来查看其它字符的编码:

package main import (    "fmt"     "unicode/utf8" )func main() {     fmt.Printf("%b\n", []byte(`:joy:`))     fmt.Printf("% x\n", []byte(`:joy:`))         r, _ := utf8.DecodeRuneInString(`:joy:`)     fmt.Printf("% b\n", r)     fmt.Printf("% x\n", r) }

Unicode 的其他编码

Unicode 当然不止一种编码,还有 UTF-16、UTF-32 等,它们的关系就是 UTF-16 用 2 个 Byte 来表示 UTF-8 分别用  1/2/3 个 Byte 来表示的字符,然后 4 个 Byte 与 UTF-8 一致,UTF-32 是完全用 4 个 Byte  来表示所有的字符,另外,详细的可以在 Comparison of Unicode encodings 中看到,

好,基础讲完,现在开始正式介绍。

Unicode 与 Golang 2

这里特别需要提到的是 Golang 与 UTF-8 的关系,他们背后的男人,都是 Ken Thompson 跟 Rob Pike 3 4 5  ,由此,大家就会明白 Golang 的 UTF-8 设计是有多么重要的参考意义。比如 Golang 设计了一个 rune 类型来取代 Code point  的意义。

rune 看源码就知道,它就是 int32,刚好 4 个 Byte,刚可以用来表示 Unicode 的所有编码 UTF-8 与 UTF-16。

在继续之前,我想帮各位明白一个事实:Golang 的源码是默认 UTF-8  编码的,这点从上面我给出的例子中就能明白,所以表情字符在编译的时候,就已经能被解析。

好了,那么我们来看看 Golang 的 unicode 包,其中就会有很多有用的判断函数:

func IsControl(r rune) bool func IsDigit(r rune) bool func IsGraphic(r rune) bool func IsLetter(r rune) bool func IsLower(r rune) bool func IsMark(r rune) bool func IsNumber(r rune) bool func IsPrint(r rune) bool func IsPunct(r rune) bool func IsSpace(r rune) bool func IsSymbol(r rune) bool func IsTitle(r rune) bool func IsUpper(r rune) bool

另外,在 src/unicode/tables.go 中,有大量的 Unicode 中,各类字符的 Code point  区间,会有比较大的参考价值。

再看看 unicode/utf8 包,这里面的函数,大多数时候你都用不到,但是有这么几类情况就需要你必须得用到了:

  • 统计字符数量;

  • 转编码,比如将 GBK 转为 UTF-8;

  • 判断字符串是否是 UTF-8 编码,或者是否含有不符合 UTF-8 编码的字符;

后面两个可以忽略,第一个需要特地提醒下:

s := `:joy:` fmt.Println(len(s))

这句输出是什么?上面提过了,刚好就是 4。于是,你不能使用 len  来获取字符数量,也就不能以此来判断用户输入的字符是不是超过了系统的限制。另外,你也不能通过 s[0] 这样的方式来获取字符,因为这样你只能取到这 4 个  Byte 中的第一个,也就是 0xf0 。

你应该做的就是把 string 转为 rune 数组,然后再去进行字符的操作。

具体的使用方法就不细谈了,相信你们能搞定。

另外,这里需要另外提示下,在 Node.js 中,string 本身就是 Unicode,而不是像 Golang 的 string  是二进制,因此在这里可以认为 Node.js 的 Buffer 才是 Golang 中的 string。

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注血鸟云行业资讯频道,感谢您对血鸟云的支持。


/template/Home/Zkeys/PC/Static