字符编码
最早的计算机系统都是使用 EBCDIC(扩展的二进制的十进制转换码) 和 ASCII 编码,因为那时候只是用一些英文字母数字,加减号和其他一些字符,字符并不多,但是随着Internet的发展,网络遍布全球。全球有大概6000种语言(其中3000种在巴布亚新几内亚…) ,为了更好地服务更多的人,我们需要为不同语言的用户提供不同的语言支持。如果世界只需要 ASCII 编码,那样将会简单很多。但事实却是非常复杂的。
字符集
character code 字符编码就是将一个字符映射到一个整数,比如最常见的 ASCII编码,将 a 编码为 97(编码点,code point), A编码为65.编码仍然是抽象的,它仍不是我们在文本或者TCP包中多见到的。 字符集常用的有ascii字符集,unicode字符集
ASCII
我们说ascii的时候,其实包含了ascii字符集和ascii编码。 ASCII 编码大家都很熟悉了,大一的时候专业基础课接触到的就是这些内容。作为最常用的编码,ASCII使用的编码点使用7-bit。所以他一共有128个编码。 这里问题来了,ASCII是一个字节,7位就能表示字符,那最左边的那一位有什么用? 回答:最高位是表示扩展字符集的。换句话说当最高位为0时,表示这一个字节就表示一个字符;如果是1,那就代表要和下一个字节连起来看,这也就是ASCII码表示汉字需要两个字节的原因。
ISO 8859
现在一个字节的标准是8个比特位,作为ASCII的扩展多出来128个编码点。一些列不同的编码集使用了这128个编码点,它们被一些欧洲语言使用,合起来就是 ISO-8859系列。 ISO-8859-1也就是常说的Latin-1,它涵盖了大部分的欧洲语言。 ISO-8859是一个系列,系列中所有的低128个编码点就是ASCII编码,以实现兼容。 早期的HTML标准推荐使用ISO-8859-1字符集。不过在 HTML 4 之后就推荐使用 Unicode了。
Unicode
像ASCII和ISO8859这样的编码在象形文字(中日韩)语言面前显得就太小气了。中文常用的字多大几千个,至少需要两个字节才能涵括。最初没有统一的国际标准,因此出现了很多的2字节编码方案,比如台湾的Big5,国内的GB2312,BGK;再考虑日本的JIS X 0208等等,字符集简直是一个大乱斗。 Unicode是一个包含所有主要当前在用字符的新的标准,它包括了欧洲,亚洲,印度等等各种语言,Unicode的好处是它是可扩展的。到5.2版本,一共有超过 107000个字符。 Unicode编码点是兼容ISO8859的,也就是说它的前256个编码点就是ISO 8859-1.要在计算机系统表示一个Unicode字符,需要使用一种编码方式。UCS(通用编码方式)使用两个字节进行编码,然而随着Unicod囊括的字符越来越多,UCS不再使用,而是使用 UTF-*的编码。 unicode字符集其实就是一个字符和整型数的映射库。它本身并不会指定需要用几个字节去代表一个字符。
utf
UTF即 Unicode Transformation format.常见的编码方式如下: UTF-32 4字节编码,不常用,尤其是 HTML5 规范明确反对使用它 UTF-16
UTF-16是一种可变长度字符编码方式,以16-bit 为单元,使用2个或4个字节为每个字符编码。 UTF-16的编码规则如下:
Unicode编码范围 (十六进制) | UTF-16编码占用字节 | UTF-16 编码(二进制) |
---|---|---|
U+0000 - U+FFFF | 2 | xxxxxxxx xxxxxxxx |
U+10000 - U+10FFFF | 4 | 110110yyyyyyyyyy 110111xxxxxxxxxx |
UTF-8 一个字符使用1-4字节,不定长度,最常用的,对英文字符基本和ISO-8859对应,中文编码为3-4字符,相UTF-8 的编码规则很简单,只有二条: 1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。 2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。 如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。
Unicode编码范围(十六进制) | UTF-8编码占用字节 | UTF-8 编码(二进制) |
---|---|---|
U+0000 - U+007F | 1 | 0xxxxxxx |
U+0080 - U+07FF | 2 | 110xxxxx 10xxxxxx |
U+0800 - U+FFFF | 3 | 1110xxxx 10xxxxxx 10xxxxxx |
U+10000 - U+10FFFF | 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
UTF-7 有时使用,但不常用 要理解Unicode和UTF-8之间的区别和联系。知道UTF的名字是Unicode转换格式就可以了。Unicode是一个字符集,UTF-8是这个字符集的一种编码方式。
Go与字符集
UTF-8 Go的字符串的每一个字符称为一个 rune,它是 int32的别名,因为一个Unicode字符的长度可能是1,2,3,4个字节,如果要统计字符数,就需要计算的是rune的个数而不是字节数了。字符数和字节数只有在是字符串只由ASCII字符组成时才是一样的。 Rune选择int32而不是uint32呢? This has been asked several times. rune occupies 4 bytes and not just one because it is supposed to store unicode codepoints and not just ASCII characters. Like array indices, the datatype is signed so that you can easily detect overflows or other errors while doing arithmetic with those types. 意思技术方便检测溢出或错误。