Golang的rune数据类型,Unicode字符编码与UTF-8字节码

Unicode编码(十六进制)UTF-8 字节流(二进制)
000000-00007F0xxxxxxx
000080-0007FF110xxxxx 10xxxxxx
000800-00FFFF1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

 

 

 

 

 

 

我的啰嗦:

Unicode编码就是对世界上所有文字进行编号,每个文字对应一个Unicode号码,凡是基于Unicode编码的文件,文件里表示字符的每个数字必然会对应Unicode的一个编码,由此对应世界上的某个文字,不会找不到,也不会找错,也就不会乱码了。比如对采用了Unicode编码方式的比如UTF-8字节码,大于255=0x0000FF的号码在ASCII码表中就找不到,此时如果强行解释就会把UTF-8的每个字节认为是一个ASCII码,自然解析出来的就是乱码了。

UTF-8做法是对Unicode编码分段后以某种方式"换算"出1~4个字节的二进制实体,这些二进制实体就是文件在磁盘上存储的字节码。为什么不直接使用Unicode码值的直接二进制字节码表示呢?Unicode码值从0~10FFFF,如果使用Unicode码值的直接二进制字节码,则每个文字都需要3个字节才能确保这3个字节作为一个整体不与其他Unicode字节码冲突。此时对0~255(0x00FF)码值的单字节ASCII字符,其3个字节的字节码的前两个字节都是二进制0,这些0不能去掉,否则就不构成一个完整的"字节码",这就造成字节流中大量重复的字节。0x0100~0xFFFF码值的双字节字符的第一个字节也是如此。

UTF-8字节码从1到4个字节,任意两个UTF-8字节码都不会形成相互包含!就是说:0x开头的单个字节肯定是单字节UTF-8字节码,110x开头的字节以及其后一个字节构成双字节UTF-8字节码,1110x开头的字节以及其后两个字节构成三字节UTF-8字节码,11110x开头的字节以及其后三个字节构成四字节UTF-8字节码。如果取得一段随机的字节流以10x开头,那如果其后第一个字节是0x开头,则从0x开头的字节往后的字节流能保证正确解释。如果10x开头的字节其后第一个字节以10x开头,其后第二个字节不以10x开头,那当前字节是被损坏乐的三字节码或四字节码,从其后第二个字节往后的字节流能保证正确解释。如果10x开头的字节其后两个字节都以10x开头,那当前字节是被损坏乐的四字节码,从其后第三个字节往后的字节流能保证正确解释。从而UTF-8字节流能够对随机取得的字节流搜索字节码准确定位一个字符。UTF-8字节码每个字节都不多余,没有全0的占位字节(比如对0~0x00FF码值的单字节ASCII字符),从而能保证文件最小。

换做是直接的Unicode码值"换算"的字节码,完整的字节流从头到尾当然也能正确解释,无非就是文件中可能含有一些全0、全1的重复字节。比如对随机取得的字节流:10 10 FF FF......这可能是1010FF  FF......,也可能是......10  10FFFF,从而Unicode的直接字节码不能对随机取得的字节流搜索字节码准确定位一个字符

《The Go Programming Language》(Go语言圣经):

总结:

UTF-8编码的缺点:

1、作为变长编码,不能通过索引(字符书✖️每个字符占用字节数)来访问第n个字符;

UTF-8的优点:

1、UTF-8编码紧凑,完全兼容ASCII码;

2、从字符串中随机字节位置,UTF-8编码可以通过回溯最多2个字节就能确定当前字节所属字节编码的开始字节的位置,不需要对字节流从头到尾紧凑遍历,不需要“字节码开头”;

3、没有任何字符的编码是其他字符编码的子串(或是另外两个字节码连接的中间部分),因此搜索一个字符时只要从字节流任意位置开始搜索它的字节码序列即可,不用担心前后的上下文会“巧合地凑出”要查找的字节码。

4、UTF-8编码的顺序和Unicode码点的顺序一致,因此可以直接排序UTF-8编码序列,结果也符合Unicode码店顺序;

5、UTF-8编码没有嵌入的NUL(0)字节,也就是说:除了0x00这一个NUL字节,不会有某个UTF-8字节码包含有0x00单字节,因而字节流只要遇到NUL字节一定是终止符,不用顾虑是否可能是其他字节码的内部0x00字节。

转载:https://www.jianshu.com/p/4fbf529926ca

rune类型:

Unicode码点对应Go语言的rune整数类型,rune又是int32等价类型,4个字节能容纳Unicode码点0~10FFFF的3个字节

我们可以将一个符文序列表示为一个int32序列。这种编码方式叫UTF-32或UCS-4,每个Unicode码点都使用对应数值的32bit来表示,是等长编码。这种方式比较简单统一,但它会浪费很多存储空间,因为大部分计算机可读的文本是ASCII字符,本来每个ASCII字符只需要8bit或1字节就可以表示。而且即使是常用的字符也远少于65536个。

// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.

//int32的别名,几乎在所有方面等同于int32
//它用来区分字符值和整数值

type rune = int32
bytestr := "try学习"
fmt.Println("len(\"try学习\"):", len(bytestr))                                       //9
fmt.Println("utf8.RuneCountInString(\"try学习\"):", utf8.RuneCountInString(bytestr)) //5
fmt.Println("len([]rune(try学习)):", len([]rune("try学习")))                           //5
runestr := []rune("try学习")
fmt.Println(reflect.TypeOf(runestr)) //[]int32,数组

golang中string底层是通过byte数组实现的,内置名字空间的len()函数作用于字符串时返回字符串占用的字节数。golang默认编码是UTF-8,指golang的数据区、堆栈存储字符串时使用UTF-8编码存储,中文字符的Unicode码是2个字节,对应UTF-8编码是3个字节,所以上面len("try学习")返回3+3*2=9。

byte类型与rune类型都用来表示字符类型:byte等同于int8,常用来处理ascii字符;rune等同于int32,常用来处理uniocde或utf-8字符。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值