计算机是如何表示字符的?
计算中的数据都是二进制(0和1),用一位来存储1个0或1,称为bit。
8个二进制序列(8个bit)为一个字节(byte)。
一个字节为现代计算机计算的最小单位。
计算机通过不同的2进制序列来表示不同的字符。如:
01100001='A'
00110000='0'
01000000='@'
1100111011010010='我'
1100111011010010 1011000010101110 1100010011100011="我爱你"
二进制序列可以计算为一个数字,比如:二进制序列(00000101)等于十进制数值5
所以也可以理解为计算机通过不同的整数来表示不同的字符
01100001=65='A'
00110000=48='0'
01000000=64='@'
1100111011010010=52946='我'
数字用其他进制表示比较长,所以一般用16进制来表示。
0x41='A'
0x30='0'
0x40='@'
0xCED2='我'
0xCED2 0xB0AE 0xC4E3="我爱你"
字符集和字符编码的相关概念
字符
: 是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。
字符表
: 是一个系统支持的所有字符的集合。
字符集
: 又称为编码字符集,是一个包含字符表中每一个字符和对应的整数映射关系的集合。
码位值
: 一个字符在某个字符集中的映射的值,一般是一个整数。
字符编码
: 是把一个码位值转换为用于存储和传输的2进制序列的方式。
上面这几个概念如下图所示:
常见的字符集
由于不同的国家和地区使用不同的文字,就衍生出了很多不同的字符集和不同的字符编码方案。如:
- 用于现代英语的ASCII字符集
- 用于欧洲很多国家的iso8859系列字符集
- 用于中国的GB2312,GBk,GB18030等字符集
- 用于台湾,香港,澳门等的Big5字符集。
- 用于日本的Shift JIS字符集
- 用于越南的VISCII
- 用于印度的ISCII
- 包含全世界所有文字符号的Unicode字符集和其UTF-7,UTF-8,UTF-16等字符编码方案。
ASCII(ascii)字符集&字符编码
ASCII
: American Standard Code for Information Interchange,美国信息交换标准代码,是基于拉丁字母的一套电脑编码系统。主要用于显示现代英语,而其扩展版本EASCII则可以勉强显示其他西欧语言。它是现今最通用的单字节编码系统(但是有被Unicode追上的迹象),并等同于国际标准ISO/IEC 646。
编码字符集
: 共定义了128个字符,包括95个可显示字符(大小写字母,阿拉伯数字数字,标点符号等)和33个控制字符(回车键、退格、换行键等)
常见编码方式
: 7位2进制就可表示128中状态,就可以表示128个字符,但计算机最小处理单位为8位,每个ascii字符用8位表示。首位补充为0.
ISO8859系列字符集和字符编码
计算机从美国发展到了欧洲。欧洲很多国家所用到的字符中,除了美国的128个ASCII字符之外,还有很多衍生的拉丁字母等字符。如在法语中,字母上方有注音符中(Éé) (Èè)(Êê)(Ëë)
;而欧洲其他国家也有各自特有的字符。
一个字节能够表示的字符可以有256个,而ASCII只使用了一个字节所能表示的256个编码中的前128个,而后128个编码相当于被闲置了。因此,欧洲各国纷纷打起了后面这128个编码的主意,导致欧洲各国各语言的单独编码的混乱局面。
编码字符集
: 为了解决各国各语言的单独编码的混乱局面,国际标准化组织(ISO)及国际电工委员会(IEC)联合制定的一系列8位元字符集的标准,现时定义了15个字符集.
- ISO/IEC 8859-1 (Latin-1) - 西欧语言
- ISO/IEC 8859-2 (Latin-2) - 中欧语言
- ISO/IEC 8859-3 (Latin-3) - 南欧语言。世界语也可用此字符集显示。
- ISO/IEC 8859-4 (Latin-4) - 北欧语言
- ISO/IEC 8859-5 (Cyrillic) - 斯拉夫语言
- ISO/IEC 8859-6 (Arabic) - 阿拉伯语
- ISO/IEC 8859-7 (Greek) - 希腊语
- ISO/IEC 8859-8 (Hebrew) - 希伯来语(视觉顺序)
- ISO/IEC 8859-8-I - 希伯来语(逻辑顺序)
- ISO/IEC 8859-9(Latin-5 或 Turkish)土耳其语。
- ISO/IEC 8859-10(Latin-6 或 Nordic)-北日耳曼语支
- ISO/IEC 8859-11 (Thai) - 泰语
- ISO/IEC 8859-12 印度天城体梵文(搁置)
- ISO/IEC 8859-13(Latin-7 或 Baltic Rim)- 波罗的语族
- ISO/IEC 8859-14(Latin-8 或 Celtic)- 凯尔特语族
- ISO/IEC 8859-15 (Latin-9)西欧语言,
加入Latin-1欠缺的芬兰语字母和大写法语重音字母,以及欧元(€)符号
- ISO/IEC 8859-16 (Latin-10) - 罗马尼亚语使用,并加入欧元符号
编码方式
: 刚好8位,直接编码即可。
中国GB系列字符集和字符编码
常见的中国字符集有:
- GB2312
- GBK
- GB18030
GB2312编码字符集
当计算机引入中国后,为了显示中文,必须重新设计一套字符集(很明显,中国汉字远远超过128个)。
新的字符集在1981年由中国国家标准总局发布,取名为GB2312或GB2312-80。全称为《信息交换用汉字编码字符集·基本集》。
只收录6763个汉字,有不少汉字,如"啰","镕"以及台湾及香港使用的繁体字,日语及朝鲜语汉字等,并未有收录在内。
GB2312中对所收汉字进行了“分区”处理,每区含有94个字符,共计94个区。即最多可表示94*94(8836个符号)
用所在的区和位来表示字符,例如“万”字在45区82位,所以“万”字的区位码是:4582。
分区如下:
- 01~09区(682个):特殊符号、数字、英文字符、制表符等,包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母等在内的682个全角字符;
- 10~15区:空区,留待扩展;在附录3,第10区推荐作为 GB 1988–80 中的94个图形字符区域(即第3区字符之半形版本)。
- 16~55区(3755个):常用汉字(也称一级汉字),按拼音排序;
- 56~87区(3008个):非常用汉字(也称二级汉字),按部首/笔画排序;
- 88~94区:空区,留待扩展。
GB2312编码方式
为了兼容ASCII字符集,GB2312规定一个小于127的字符的意义与原来相同。
但两个大于127的字符连在一起时,就表示一个GB2312字符。
每个字符以两个字节来表示。第一个字节称为“高位字节”,第二个字节称为“低位字节”。“高位字节”使用了0xA1–0xF7(把01–87区的区号加上0xA0),“低位字节”使用了0xA1–0xFE(把01–94加上0xA0)。
中文的半角和全角
在GB2312中除了包含常用中文字符外,还把数学符号、罗马希腊字母、日文的片假名等都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在ASCII中的那些符号就叫"半角"字符了。
GBK编码字符集
GB2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。但对于人名、古汉语等方面出现的罕用字和繁体字,GB2312不能处理,于是微软利用GB2312未使用的编码空间,对其进行扩展形成了GBK编码。共收录21886个汉字和图形符号,其中汉字(包括部首和构件)21003个,图形符号883个。
GBK向下完全兼容GB2312-80编码。支持GB2312-80编码不支持的部分中文姓,中文繁体,日文假名,还包括希腊字母以及俄语字母等字母。
GBK编码方式
字符有一字节和双字节编码,00–7F范围内是第一个字节,和ASCII保持一致
之后的双字节中,前一字节是双字节的第一位。总体上说第一字节的范围是81–FE(也就是不含80和FF),第二字节的一部分领域在40–7E,其他领域在80–FE。
GB18030编码字符集
但GBK自身并非国家标准,所以由国家质量技术监督局于2000年3月17日发布了最新的字符集,称之为GB18030,全称为国家标准GB 18030-2005《信息技术 中文编码字符集》。
共收录汉字70244个,与GB2312完全兼容,与GBK基本兼容。
GB 18030主要有以下特点:
- 采用变长多字节编码,每个字可以由1个、2个或4个字节组成。
- 编码空间庞大,最多可定义161万个字符。
- 支持中国国内少数民族文字,不需要动用造字区。
- 汉字收录范围包含繁体汉字以及日韩汉字。
GB18030编码方式
GB18030包含三种长度的编码:单字节的ASCII、双字节的GBK(略带扩展)、以及用于填补所有Unicode码位的四字节UTF区段。GBK双字节部分通过查表定义,而四字节部分则根据之前两个部分没有提到的通用字符集码位顺序填补。由于和GBK兼容,GB 18030在搜索ASCII字符时也需要使用特别代码进行判断。
大五码(Big5)字符集和字符编码
“大五码”(Big5)是由台湾财团法人信息产业策进会为五大中文套装软件所设计的中文共通内码,在1983年12月完成。除了台湾外,其他使用繁体汉字的地区,如香港(香港增补字符集)、澳门(澳门增补字符集),及使用繁体汉字的海外华人,都曾普遍使用Big5码做为中文内码及交换码。
编码字符集和编码方案
Big5码是一套双字节字符集,共收录13,060个汉字,使用了双八码存储方法,以两个字节来安放一个字。第一个字节称为“高位字节”,第二个字节称为“低位字节”。
“高位字节”使用了0x81-0xFE,“低位字节”使用了0x40-0x7E,及0xA1-0xFE。在Big5的分区中:
- 0x8140-0xA0FE 保留给用户自定义字符(造字区)
- 0xA140-0xA3BF 标点符号、希腊字母及特殊符号,
- 包括在0xA259-0xA261,安放了九个计量用汉字:兙兛兞兝兡兣嗧瓩糎。
- 0xA3C0-0xA3FE 保留。此区没有开放作造字区用。
- 0xA440-0xC67E 常用汉字,先按笔划再按部首排序。
- 0xC6A1-0xC8FE 保留给用户自定义字符(造字区)
- 0xC940-0xF9D5 次常用汉字,亦是先按笔划再按部首排序。
- 0xF9D6-0xFEFE 保留给用户自定义字符(造字区)
Unicode和UCS
当计算机传到世界各个国家时,为了适合当地语言文字,都会实现各自的一套编码方案。各国和地区在本地使用没有问题,当互联网出现时,各个国家地区相互沟通交流就会出现乱码现象。
为了解决这个问题,历史上存在两个组织尝试创立单一字符集而且相互都不知道对方的存在,即国际标准化组织(ISO)于1984年创建的ISO/IEC(后文简称ISO)和由Xerox、Apple等软件制造商于1988年组成的统一码联盟(后文简称统一码联盟)。
ISO工作组制定的标准称为通用字符集(Universal Character Set),简称UCS。
统一码联盟制定的标准称为Unicode字符集。
1991年前后,两个项目的参与者都认识到,世界不需要两个不兼容的字符集。于是,它们开始合并双方的工作成果,但两个项目仍都独立存在,并独立地公布各自的标准。不过统一码联盟和ISO/IEC都同意保持两者标准的码表兼容,并紧密地共同调整任何未来的扩展。由于Unicode这一名字比较好记,因而它使用更为广泛。后文仅介绍Unicode。
编码字符集
Unicode采用计划四个字节表示一个字符,首位恒为0,理论上最多能表示个字符,完全可以涵盖一切语言所用的符号。但目前Unicode字符分为17组编排,每组称为平面(Plane),而每平面拥有65536(即2^16)个代码点。然而目前只用了少数平面。
平面 | 始末字符值 | 中文名称 | 英文名称 |
---|---|---|---|
0号平面 | U+0000 - U+FFFF | 基本多文种平面 | Basic Multilingual Plane,简称BMP |
1号平面 | U+10000 - U+1FFFF | 多文种补充平面 | Supplementary Multilingual Plane,简称SMP |
2号平面 | U+20000 - U+2FFFF | 表意文字补充平面 | Supplementary Ideographic Plane,简称SIP |
3号平面 | U+30000 - U+3FFFF | 表意文字第三平面(未正式使用) | Tertiary Ideographic Plane,简称TIP |
4号平面至13号平面 | U+40000 - U+DFFFF | (尚未使用) | |
14号平面 | U+E0000 - U+EFFFF | 特别用途补充平面 | Supplementary Special-purpose Plane,简称SSP |
15号平面 | U+F0000 - U+FFFFF | 保留作为私人使用区(A区) | Private Use Area-A,简称PUA-A |
16号平面 | U+100000 - U+10FFFF | 保留作为私人使用区(B区) | Private Use Area-B,简称PUA-B |
目前最常用的是基本多文种平面(Basic Multilingual Plane, BMP),或称第0平面或0号平面(Plane 0)。编码从U+0000至U+FFFF。
中文在Unicode中分布
Unicdoe1.1,收集中日韩三个国家的中文字符,共20,902个字,分布在U+4E00–U+9FFF这个区域。
Unicode3.0,于U+3400–U+4DFF加入了6,582个字。
Unicode3.1,于U+20000–U+2A6FF加入了42,711个字。
Unicode4.1,于U+9FA6-U+9FB3和U+9FB4-U+9FBB共加入了22个字。
Unicode5.1,于U+9FBC-U+9FC2加入了7个日语汉字。
...
Unicode10.0,于U+2CEB0-U+2EBEF和U+9FD6-U+9FEA加入7494个汉字。
目前累计unicode中共收录了87,882个中文字符。
但常用中文范围为0x4E00—0x9FA5之内,如验证用户输入是否是中文,即可采用此范围。
编码方案
Unicode字符在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。
例如,如果一个仅包含基本7位ASCII字符的Unicode文件,如果每个字符都使用2字节的原Unicode编码传输,其第一字节的8位始终为0。这就造成了比较大的浪费。
Unicode的转换格式(Unicode Transformation Format,简称为UTF),常见编码转换方案如下:
UTF-32
UTF-32编码长度是固定的,UTF-32中的每个32位值代表一个Unicode码位,并且与该码位的数值完全一致。
UTF-32的主要优点是可以直接由Unicode码位来索引。
UTF-32的主要缺点是每个码位使用四个字节,空间浪费较多。
UTF-16
UTF-16编码长度是不固定的,如果字符编码U小于0x10000,也就是十进制的0到65535之内,则直接使用两字节表示;
如果字符编码U大于0x10000,由于UNICODE编码范围最大为0x10FFFF,从0x10000到0x10FFFF之间共有0xFFFFF个编码,也就是需要20个bit就可以标示这些编码。用U'表示从0-0xFFFFF之间的值,将其前 10 bit作为高位和16 bit的数值0xD800进行 逻辑or 操作,将后10 bit作为低位和0xDC00做 逻辑or 操作,这样组成的 4个byte就构成了U的编码。
16进制编码范围 | UTF-16表示方法(二进制) | 10进制码范围 | 字节数量 |
---|---|---|---|
U+0000~U+FFFF | xxxxxxxx xxxxxxxx yyyyyyyy yyyyyyyy | 0-65535 | 2 |
U+10000~U+10FFFF | 110110yyyyyyyyyy 110111xxxxxxxxxx | 65536-1114111 | 4 |
UTF-16的大端序(BE)和小端序(LE)
不同的计算机系统会以不同的顺序保存字节。这意味着字符U+4E2D在UTF-16编码方式下可能被保存为4E 2D或者2D 4E,这取决于该系统使用的是大尾端(big-endian)还是小尾端(little-endian)。
其中Windows和linux操作系统内核中使用的为UTF-16小端序,而Mac OS则使用大端序。
如某字符为十六进制编码4E59,按两个字节拆分为4E和59
在Mac上读取时是从低字节开始,那么在Mac OS会认为此4E59编码为594E,找到的字符为“奎”,而在Windows上从高字节开始读取,则编码为U+4E59的字符为“乙”。
就是说在Windows下以UTF-16编码保存一个字符“乙”,在Mac OS环境下打开会显示成“奎”。
所以为了弄清楚UTF-16文件的大小尾序,在UTF-16文件的开首,都会放置一个U+FEFF
字符作为Byte Order Mark(BOM)(UTF-16LE以FF FE代表,UTF-16BE以FEFF代表),以显示这个文本文件是以UTF-16编码,其中U+FEFF
字符在UNICODE中代表的意义是ZERO WIDTH NO-BREAK SPACE(零宽度非换行空格)。
Unicode编码
相当于UTF-16的小端序(LE),任何字符都使用两个或四个字节表示。
Unicode big endian
相当于UTF-16的大端序(BE),任何字符都使用两个或四个字节表示。
UTF-8
UTF-8是可变长度字符编码。是互联网中应用中优先采用的编码。
UTF-8使用1至4个字节为每个字符编码。具体规则如下:
范围 | Byte 1 | Byte 2 | Byte 3 | Byte 4 |
---|---|---|---|---|
U+0000~U+007F | 0xxxxxxx | |||
U+0080~U+07FF | 110xxxxx | 10xxxxxx | ||
U+0800~U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | |
U+10000~U+10FFFF | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
小练习
: 请把字符U+FEFF使用UTF-8表示?
其他UTF
已走入历史而很少再被使用UTF-7
尚未被完整开发的UTF-6和UTF-5
ANSI编码
为使计算机支持更多语言,通常使用 0x0080~0xFFFF 范围的 2 个字节来表示 1 个字符。不同的国家和地区制定了不同的标准,由此产生了 GB2312、GBK、GB18030、Big5、Shift_JIS等各自的编码标准。这些使用多个字节来代表一个字符的各种汉字延伸编码方式,称为ANSI 编码。
ANSI编码表示英文字符时用一个字节,表示中文用两个或四个字节。
在简体中文Windows操作系统中,ANSI 编码代表 GBK编码;
在繁体中文Windows操作系统中,ANSI编码代表Big5;
在日文Windows操作系统中,ANSI 编码代表 Shift_JIS 编码。
不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。
练习
- 请把下面的2进制序列转换为字符。
11101111 10111011 10111111
11100110 10001000 10010001
11100111 10001000 10110001
11100100 10111101 10100000
00110001 00110011 00110001
00110100 11100100 10111000
10101101 11100101 10011011 10111101 - 请查询出“联通”两个字符的GBK编码。
- 一个中文到底占几个字节呢?
- String s="a𤋮";s.length()==?