Unicode
Unicode统一码又称为万国码或单一码,是计算机科学领域中的一项业界标准,包含字符集、编码方案等。
Unicode统一码是为了解决传统字符编码方案的局限而产生,它为每种语言中每个字符设定了统一且唯一的二进制编码,以满足跨语言、跨平台进行文本转换和处理的要求。
Unicode统一码是基于通用字符集(Universal Character Set)标准发展而来的,Unicode字符集简称为UCS(Unicode Character Set),早期的Unicode标准有UCS-2、UCS-4说法。
Unicode编码系统可分为编码方式和实现方式两个层次
编码方式上,Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案,采用数字0到0x10FFFF来映射所有的字符,最多可容纳1114112个字符。从数字0开始为每个符号会指定一个编号,这个编号叫做Code Point,翻译为码元、码位、码点都有,都是指可以分配给字符的数字。码点规定使用U+
随后紧接着十六进制数来表示。
例如:Unicode码点0的符号是null,表示所有二进制位都是0。
U+0000 = null
目前最新版的Unicode7.0共收录了109449个符号,中日韩文字位74500个,东南亚文字占了全球现有符号的2/3。如此多的符号Unicode并不是一次性定义的,而是采用分区定义的方式。规定每个区可存放65536个字符,一个区又称为一个平面(plane),目前共有17个平面。在所有字符为最前面的65535个字符位称为基本平面(BMP),码点范围从0到65535,十六进制表示从U+0000到U+FFFF。基本平面存放着最常用的字符,这也是Unicode最先定义和公布的一个平台。剩余字符都存放在辅助平面(SMP),码点范围U+010000到U+10FFFF。
实现方式上,Unicode指规定了每个字符的码点,具体采用什么样的字节序表示码点就涉及到了编码方法。编码方式目的将数字表示为程序中数据,最直观的编码方法是每个码点使用4个字节表示,字节内容一一对应码点,这种编码方法就叫做UTF-32。
比如:码点0的UTF-32表示方式
U+0000 = 0x00 00 00 00
UTF-32编码方案的优点在于,转换规则简单直观,查找效率高,时间复杂度O(1)。缺点在于浪费空间,同样内容的英文文本会比ASCII编码大4倍。这个缺点很致命,导致实际上没有人使用,比如HTML5标准就明文规定,网页编码不得采用UTF-32。
UTF是UCS Transformation Format的缩写,翻译为Unicode字符集转换格式,即怎样将Unicode定义的数字转换称为程序数据。
UTF-8
为了节省空间就导致了UTF-8的诞生,UTF-8是一种变长的编码方法,字符长度从1个字节到4个字节不等。越是常用的字符,字节越短,最前面的128个字符只使用1个字节表示,与ASCII码完全相同。
UTF-8又称为8位元,是针对Unicode的一种可变长度字符编码。可以用来表示Unicode标准中的任何字符,其编码中的第一个字节仍与ASCII相容。
UTF-8使用1到4个字节为每个字符编码
- 一个ASCII字符,只需要1字节编码。
- 带变音符号的拉丁文、希腊文、西里尔等字母,需要2字节编码。
- 中日韩文字、东南亚文字、中东文字等包含大量常用字,需要3字节编码。
- 极少使用的语言会使用4字节编码
byte
字节是计算机用于计量存储容量的一种单位,是二进制数据的单位,一个字节通常8位长。Go语言中byte
是uint8
类型的别名,一个字节存储8位无符号数,存储的数值范围从0到255。byte
可用于表示ASCII
码表中的一个字符,传统ASCII
编码的字符每个只占1字节。
数据类型 | 别名 | 数据范围 | 描述 |
---|---|---|---|
uint8 | byte | 0~255 | 可表示ASCII字符 |
例如:ASCII码表中大写字母A对应的十进制数值为65,对应十六进制数值为41。
var b byte = 65
fmt.Printf("ascii = %v, unicode = %U, char = %c, hex = %x\n", b, b, b, b)
// ascii = 65, unicode = U+0041, char = A, hex = 41
注意:格式化说明符%c
表示字符(char),当与字符配合使用时%v
或%d
会输出字符对应的整数,%U
输出格式为U+hhhh
的字符串。
char
和其它语言不同的是Go语言中没有字符这种数据类型,字符只是整数的特殊用例。在Go中具两个用来表示字符的整型别名分别是byte
和rune
。
type byte = uint8
type rune = int32
-
byte
是uint8
的别名,长度为1个字节,用来表示ASCII字符。 -
rune
是int32
的别名,长度为4个字节,用来表示UTF-8编码的Unicode。
既然byte
和rune
都能表示字符,为什么还需要两种呢?由于byte
占用1个字节,因此可用来表示ASCII字符。Go默认编码方式为UTF-8,UTF-8采用的是变长的编码方式,字符长度从1到4个字节不等。对于具有2个字节以上的字符,此时byte
就无能无力了。因此就需要rune
。
string
Go语言中字符串string
本质上是一个只读的字节切片,由于是只读的因此字符串内容一旦被创建是不能被修改的。如需修改需将字符串先转换为[]byte
字节切片或[]rune
符文切片再操作。
当使用for...range
遍历字符串时,Go会自动将字符串转换为[]rune
后再执行遍历,即按字符遍历。而使用for
循环字符串时,不会发生自动转换,默认会按字节遍历。
例如:按字节遍历字符串
s := "字符串str"
for i := 0; i < len(s); i++ {
fmt.Printf("%+v %c\n", s[i], s[i])
}
229 å
173
151 �
231 ç
172 ¬
166 ¦
228 ä
184 ¸
178 ²
115 s
116 t
114 r
例如:按字符遍历字符串
//字符遍历
s := "字符串str"
for i, v := range s {
fmt.Println(i, v, fmt.Sprintf("%c", v))
}
0 23383 字
3 31526 符
6 20018 串
9 115 s
10 116 t
11 114 r
网友评论