Go语言——字符串和编码

声明:下面的许多知识点来自:https://blog.csdn.net/qq_36431213/article/details/83029133 和 https://www.liaoxuefeng.com/wiki/1016959663602400/1017075323632896 以及 https://zhuanlan.zhihu.com/p/38333902 下面只是以自己的理解做了个整理

为了讲清楚字符串的编码,我们先明确下如下几个定义;

  1. 字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。
  2. 字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其他东西的一个集合(如号码或电脉冲)进行配对。即在符号集合与数字系统之间建立对应关系,它是信息处理的一项基本技术。通常人们用符号集合(一般情况下就是文字)来表达信息。而以计算机为基础的信息处理系统则是利用元件(硬件)不同状态的组合来存储和处理信息的。元件不同状态的组合能代表数字系统的数字,因此字符编码就是将符号转换为计算机可以接受的数字系统的数,称为数字代码。

常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。

正式进入我们的话题,以问题的形式来研究这个事情

计算机只能处理数字,因为它只认识二进制,就是0101010,那怎么让计算机来处理文本,处理字符呢?

答案就是编码;比如在ASCII编码中,我们用编码数字65表示 大写字母 A。由于计算机是美国人发明的,他们为了可以处理字符,就把大小写字母、数字和一些符号集合成一个字符集,然后给为这些字符分配一个编码,也就是建立一个从编码到字符的映射关系表。这其实就是ASCII编码。所以说ASCII编码包含了ASCII字符集和其字符编码方式

ASCII编码对于美国人来说,确实够用了,但是随着互联网的发展,其他国家也需要编码呀,比如汉语,我要怎么用计算机来表达“中”呢?怎么让计算机跟认识字母“A”一样认识“中”呢?

方法当然还是一样咯,还是编码,所以呢,我们制定了GB2312编码,建立了一个中文字符集,和这个字符集到数字之间的映射关系。但是还有问题,一个国家,一个编码方式吗?每个国家一个标准,那在一个多语言混合的文本中,就会出现乱码;什么是乱码,就是计算机不知道怎么解读二进制串,转成正确的字符,或者说使用了错误的字符编码方式进行解读,字符编码与字符集不对应自然就出现了乱码。

如何解决这种乱码问题呢?

答案是标准,也就是现在的Unicode,Unicode把所有语言的字符都统一到一套编码里。这样问题就解决了,大家都用同一套字符集和字符编码。

ASCII编码是1个字节,而Unicode编码通常是两个字符,比如

汉字已经超出了ASCII编码的范围,其Unicode编码\u4e2d(\u表示unicode编码),换成对应的二进制就是01001110 00101101,十进制是20013

字母A用ASCII编码是十进制的65,二进制的01000001;其Unicode编码只需要在前面补0就可以,因此,A的Unicode编码是00000000 01000001

这样我们解决了乱码问题,但是很浪费空间,比如说,我们有一个英文文档,如果用Unicode编码的话,会比ASCII编码多出一倍的存储空间。如何解决呢?

为了节约存储和提高传输效率,就出现了UTF-8编码;其实就是针对Unicode字符集,使用不同的字符编码方式;UTF-8是一种变长编码试,它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8 的编码规则很简单,只有二条:

  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
  2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

根据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。

"中"的 Unicode 是\u4e2d(01001110 00101101),根据上表,可以发现4e2d处在第三行的范围内(0000 0800 到 0000 FFFF),因此中的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从中的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,中的 UTF-8 编码是11100100 10111000 10101101,转换成十六进制就是e4b8ad。(所以呢,"中"占了三个字节)

经过上面的知识铺垫,我们来看下,在go中的string、byte、rune的区别?

什么叫string呢,其定义是"A string is an immutable sequence of bytes",byte是uint8的别名 (type byte uint8),而rune呢,就是int32的别名(type rune int32),这些别名其实就是告知编译器如何解读这些二进制串而以;另外我们还要知道,go里面是如何定义这个rune的,“assigns each unicode characters a standard number which called a Unicode code point or,in Go terminology, a rune”所以这个rune就是每个unicode字符的编码值了,我们看下面的程序

package main
import (
	"fmt"
)

func main() {
	s := "中"
	bytes := []byte(s)
	runes := []rune(s)
	fmt.Printf("%x\n", s)  //输出:e4b8ad
	fmt.Println(len(s))    //输出: 3
	fmt.Printf("%x\n", bytes) //输出: e4b8ad
	fmt.Println(len(bytes)) //输出: 3
	fmt.Printf("%x\n", runes) //输出:4e2d
	fmt.Println(len(runes)) //输出:1
}

上面的%x表示使用16进制输出,通过上面的输出可以看出来,go里面string的字符编码是UTF-8,string的底层其实就是一个byte数组,而内置函数len作用在string上时,其实就是返回这个string的byte数组的长度了,而非其rune表示;可以说

  • byte 的操作单位是一个字节,可以理解为一个英文字符
  • rune 的操作单位是一个字符,不管这个字符是什么字符
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值