前言
记得最初学习语言的时候,对于字符编码的概念搞不清楚,网上的言论总是感觉戳不到自己的痒点,对于轻度强迫症来说,蓝瘦啊。随着在it行业浸淫许久,自己遥想当年那过不去的坎,今天也写一些关于字符编码的简介,简单,希望能帮助大家解决疑问。
字符集和字符编码
字符集,就是说字符的集合,比如汉字,就是一个字符集,其中包括了所有的汉字,以及一定的字典中排序,字符集针对的是字符。
字符编码,是字符集和计算机世界的映射,比如汉字那么多,如何让计算机识别呢,那么就有一个字符编码,标明"芳"---->01010101(仅是举例)等等。字符编码针对的是字符到01的映射。
Unicode和Utf
unicode就是字符集,囊括了几乎所有文字字符,对每一个文字字符都给予一个编号进行排序。就像汉字一样。
utf是字符编码,是将每一个文字字符映射到计算机世界的映射表。分为utf-8,utf-16,utf-32,就是将unicode映射到计算机二进制编码的三种方式。发现没有,后缀都是8的倍数,因为一个Byte是8Bit,所以utf-8是以一个字节作为基本单位,utf-16是两个字节作为基本单位,utf-32是以4个字节作为基本单位。现在的utf-8中ascii部分保持一个字节和ASCII码保持兼容,汉字一般都是3个字节,因其良好的兼容性和对内存的节省被广泛应用。
Java与Unicode
java内部采用unicode字符集进行存储,并根据你系统的编码集,将unicode字符映射到系统编码集,因为unicode几乎囊括了世界上所有的字符。比如mac笔记本系统用的是utf-8,那么直接将该字符对应的编码输入计算机,计算机就可以识别并显示,映射过程为unicode序号-->utf-8二进制编码-->输入给系统。比如你用的windows是gbk,而“囧"字在unicode编号(注意是编号不是编码)是35430,那么只需要知道"囧"字在gbk中的编号是4567,再用gbk的编码集,将4567序号的字符翻译成对应的二进制1000110101编码,输入给计算机系统,那么系统就能够正常显示“囧"字啦,映射过程为unicode序号-->gbk序号-->gbk二进制编码-->计算机系统读取。这就是java跨国际的能力秘密。
UTF-8编码形式
UTF-8编码是Unicode字符集的一种编码方式,其特点是使用变长字节数来存储数据。一般是1到4个byte,当然,也可以更长,实际上4个byte可以表示2的32次方个不同字符,即4294967296个(约43亿),已经足以编码人类现使用的绝大部分字符了。
为什么要变长呢?你可以理解为按需分配,比如一个字节足以容纳所有的ASCII码字符,那何必补一堆0用更多的字节来存储呢?实际上变长编码有其优势也有其劣势,优势是节省空间、自动纠错性能好、利于传输、扩展性强,劣势是不利于程序内部处理,比如正则表达式检索,UTF-16、UTF-32这些等宽字符编码就比较适合程序处理,但是又比较耗存储空间。那UTF-8编码实现是怎样的呢?
我们已经知道UTF-8编码至少有一个字节,从首字节就可以判断一个字符的UTF-8编码有几个字节。如果首字节以0开头,肯定是单字节编码,如果以110开头,肯定是双字节编码,如果是1110开头,肯定是三字节编码,以此类推。除了单字节外,多字节UTF-8码的后续字节均以10开头。
所以1~4字节UTF-8编码看起来是这样的:
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
单字节可编码的Unicode范围:\u0000~\u007F(0~127)
双字节可编码的Unicode范围:\u0080~\u07FF(128~2047)
三字节可编码的Unicode范围:\u0800~\uFFFF(2048~65535)
四字节可编码的Unicode范围:\u10000~\u1FFFFF(65536~2097151)
127、2047、66535、2097151这几个临界值怎么来的?因为UTF-8编码含有用于标识编码的0、110、1110等,所以1~4个字节的UTF-8编码有效位数分别为7、11、16、21。