浅析汉字编码方式

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情
最近稍微研究了一下汉字的几种编码方式,感觉收获颇多,在此罗列出来,以供需要的朋友参考。因为网上讨论此话题的文章也颇多,我的一点见解似乎早就被前辈们覆盖到,所以,本文就当是写给自己的小小的总结吧。
GB2312
似乎是最普通的编码方式。80年代诞生,收录6000多汉字。几乎所有的中文系统都会支持GB2312。
GB2312的编码方式和古老的区位码颇有渊源。汉字的区位码每两位加上0xA0就是计算机中的GB2312码。比如“啊”区位码是1601,GB码是0xB0A1。B0 = 16 + A0,A1 = 01 + A0。
几乎所有的关于GB2312的资料都会说,它使用两个字节来存放汉字和符号。我对此颇为怀疑。在我的印象里,GB码似乎都是DBCS(double-byte character sets),即同时使用1个字节和2个字节两种方式来表示一个字符。不知道是不是我的理解问题。在Windows中有一个小程序“字符映射表”。这是个很有用的东西。通过它查找,Windows中,中文简体字符集的编码是同时用1个字节和2个字节来表示的。当高位是0x00~0x7f时,为一个字节,高位为0x80以上时用2个字节表示。
GBK
是GB2312的扩展方案,使用了原来编码空间的一些空白,增加了一些汉字,因此向下兼容GB2312。是Windows中文系统的缺省字符集。
可以用Windows的记事本看一看GBK的编码。打开记事本写几个字:“在CSDN写Blog”。保存类型为“ANSI”。注意ANSI是英语文字的编码方式(美国国家标准么),可不是汉字的。这里“ANSI”的意思就是采用系统默认的字符编码方式编码。
用一个16进制编辑器打开保存的文件,内容是:
D4 DA 43 53 44 4E D0 B4 42 6C 6F 67
    分析一下:
D4
DA
43
53
44
4E
D0
B4
42
6C
6F
67
C
S
D
N
B
l
o
g
很明显单字节和双字节是一起使用的。
用过DOS的朋友都会记得汉字的乱码。若将上面每一个字节按照ASCII对应为字符,就可以看到乱码了:
╘┌CSDN╨┤Blog
因为ASCII扩展中0x80以上的字符都是非英语字母和制表符。因此汉字乱码看上去总是那么怪怪的。
DBCS总会碰到的一个问题就是错位。相信每个人都曾在网页上见到过一小片一小片的乱码。因为每一个汉字(准确的说是全角符号)都是两个字节拼成的。若是丢掉了其中一个字节,那么显示就会出现错乱。比如上面这一行字,我把开头的D4删掉,变成了:
贑SDN写Blog
因为第二个字节0xDA仍然大于0x7f,因此系统将0xDA43当作一个汉字输出了(可以查一下字符映射表证实一下),而剩下的“SDN”照常输出。若这是一长串的汉字没有任何一个半角字符做“缓冲”的话,就要乱成一片了。
GB18030
国内最新的编码方案。支持了更多的字符,甚至包括了蒙文,藏文之类。
GB18030的独特之处在于它向下兼容了GBK,但又扩展了编码空间。GB18030采用1字节,2字节,4字节三种方式来编码。其中:
1字节从0x00~0x7f;
2字节的高端从0x81~0xfe,低端从0x40到0x7e,以及0x80到0xfe;
4字节从0x81308130~0xfe39fe39。
GB18030有一个非常庞大的编码空间,几乎覆盖了现在所有编码方式的字符。它的4字节编码方式因为太过独特,似乎给微软造成了不少麻烦。现在WinXP和Win2K可以通过Add-Ones支持GB18030,它的代码页是54936,然而因为这些系统平台都不能支持4字节的码页(Code Page),因此内核仍然是GBK的,GB18030只是空有一个代码页而已。要想让这些系统支持GB18030,需要改写系统底层的许多代码。
在这些系统上,一些软件会认为系统的默认编码方式是GB18030(Java就是这样)。但实际上系统默认码页仍然是GBK。这些系统虽然有18030的字体(宋体18030),但并不能处理所有GB18030的符号,因为系统并不支持4字节的编码。但据我编程证实,JDK 1.5可以支持GB18030的四字节编码。
Unicode
国际统一的编码方式。据我理解,似乎Unicode标准试图用2个字节覆盖全世界所有的书写符号,两字节总共65535个编码位,据说现在还剩下3w多没有编码。前途无量,前途无量。
Unicode是真正的纯两个字节的编码方案。所有的字符一视同仁,原有的ASCII字符通过在高位加00来兼容Unicode。这使得Unicode成为非常危险的编码方案。一旦某一个字节丢失,其后的信息将全部作废。
在Windows的记事本中保存文件时可以选择Unicode以及Unicode Big Endian两种方式。在这里多说几句。关于Big Endian和Little Endian的含义不想多说。为什么Unicode要分大尾和小尾,而GBK不用?因为Unicode本身就是双字节码,双字节是放在一起作为一个单元的。而GBK本质上讲是单字节的,每一个字节是单独处理的。因此不能分大尾和小尾。在字符映射表中查到“在”的代码是0xD4DA,保存后就是0xD4DA。
“在CSDN写Blog”保存为Unicode编码后,文件内容是:
FF FE 28 57 43 00 53 00 44 00 4E 00 99 51 42 00 6C 00 6F 00 67 00
FF FE是Unicode码串的头,是固定的。不要以为是记事本这个软件的自创。其后每两个字节是一个字符。应该注意到英文字符的编码与ASCII是兼容的。
保存为Unicode Big Endian后的文件内容是:
FE FF 57 28 00 43 00 53 00 44 00 4E 51 99 00 42 00 6C 00 6F 00 67
编码的顺序和头的样子都变化了。
试试删掉一个字节。小心Unicode的头部不能动。以Little Endian的为例,删掉FF FE后面的28,文字变成了:
䍗匀䐀一餀䉑氀漀最
完全没有意义。
UTF
关于UTF的含义,我看到了两个不同的解释。在 http://www.dvpos.com/blog(周海汉的开发专栏)中的《深入剖析JSP和Servlet对中文的处理过程》(以下简称《深入》)一文中说是Unicode Text Format的缩写。在另一个地方 http://fmddlmyy.home4u.china.com中的《谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词》(以下简称《谈谈》)一文中说是UCS Transformation Format的缩写。而UCS是Unicode Character Set的缩写。感觉似乎后者更可能一些。
从《谈谈》一文中得知,UTF-8的编码规则为:
Unicode
UTF-8
0000 - 007F
0xxxxxxx
0080 - 07FF
110xxxxx 10xxxxxx
0800 – FFFF
1110xxxx 10xxxxxx 10xxxxxx
《深入》一文中对于以上规则有如下的文字描述:
1.        如果Unicode的16位字符的头9位是0,则用一个字节表示,这个字节的首位是“0”,剩下的7位与原字符中的后7位相同,如“/u0034”(0000 0000 0011 0100),用“34” (0011 0100)表示;(与源Unicode字符是相同的);
2.        如果Unicode的16位字符的头5位是0,则用2个字节表示,首字节是“110”开头,后面的5位与源字符中除去头5个零后的最高5位相同;第二个字节以“10”开头,后面的6位与源字符中的低6位相同。如“/u025d”(0000 0010 0101 1101),转化后为“c99d”(1100 1001 1001 1101);
3.        如果不符合上述两个规则,则用三个字节表示。第一个字节以“1110”开头,后四位为源字符的高四位;第二个字节以“10”开头,后六位为源字符中间的六位;第三个字节以“10”开头,后六位为源字符的低六位;如“/u9da7”(1001 1101 1010 0111),转化为“e9b6a7”(1110 1001 1011 0110 1010 0111);
试试把“在CSDN写Blog”转化成UTF-8编码,内容变成:
EF BB BF E5 9C A8 43 53 44 4E E5 86 99 42 6C 6F 67
原来的字头FF FE根据规则变成了EF BB BF。即:
原来:1111 1110 1111 1111(FF FE à FE FF,因为Little Endian)
UTF:1110 1111 1011 1011 1011 1111,即EF BB BF
再试试“在”的编码,
原来:0101 0111 0010 1000(“在”的Unicode码是0x5728)
UTF:1110 0101 1001 1100 1010 1000,即E5 9C A8。
由此,验证了UTF-8的编码,而且注意到,UTF-8也被当成了单字节码一样对待,因为并没有大尾小尾的区别。
对于汉字居多的文本来说,UTF-8将大部分是每个汉字三个字节的情况,反而会增加了码长。但UTF-8的一大好处就是避免了Unicode“一个烂鱼坏得一锅腥”的糟糕情况。因为UTF-8每一个字有严密的编码规则,如果传输中丢掉了一个字节,结果不会影响很多。比如我们的例子中,删掉除头之外第一个字节E5,会使其后的9C A8都不符合编码规则,这样会识别出坏掉的字,丢掉它们之后,后面的“CSDN写Blog”仍然会保留。
ISO-8859-1
最后说一下ISO-8859-1是因为它根本就不是汉字编码。据“维基百科”记载,ISO 8859是给除英语之外的其他字母文字做编码规范的。它占用ASCII码的0xA0~0xFF,每个字符集扩展96个字符。ISO-8859(多了一个连字号)则是ISO 8859加上原有的ASCII中的字符构成的编码规范。
说到ISO-8859-1因为它是许多未汉化的西文操作系统的编码,比如Linux。最主要的原因是我发现我的手机的缺省编码也是它。许多西文的数据库等等也只认识8859规范。
我们常接触的就是8859-1,实际上8859这套规范很大,似乎有16套之多(ISO 8859-1~ISO 8859-16)。
8859规范其实很简单。相对于DOS时的ASCII,它只不过是另一种扩展ASCII的方式。回头看一下DOS下的汉字乱码(GBK部分有写),在ISO-8859-1编码方式下显示汉字时的乱码原理本质上和DOS时是一样的,它们都是将汉字的双字节解释成两个单独的ASCII字符,只不过两者对于ASCII的扩展是不一样的,因此乱码的样子看起来也不太一样。但是在内存中,汉字的编码并没有丢失。只要改变一种编码方式,真相就会大白。
将“在CSDN写Blog”,转化为ISO-8859-1编码显示出来是:
ÔÚCSDNдBlog
这也是IE显示一些中文网页时出现的乱码的种类之一。
 
P.S. 我用Java做这些编码之间的转换实验时无意中发现Java支持GB18030的四字节表示方法。在将把ISO-8859-1转化后的例子直接getBytes()时,发现结果是:
81 30 88 38 81 30 89 33 43 53 44 4e 81 30 88 34 81 30 85 37 42 6c 6f 67
这些“81 30”实在让我迷糊了半天。后来注意到GB18030的编码方式才明白,81 30 88 38正好在GB18030四字节编码的范围内。猜测GB18030使用扩展出的四字节部分编码这些西欧字符,而Java认为我的机器的默认编码是GB18030,使用getBytes()时就采用了GB18030进行编码,而将ISO-8859-1转化出的那些西欧文字转化到GB18030时,就产生了这些四字节的编码。
 
 
参考链接:
周海汉的开发专栏: http://www.dvpos.com/blog
 
微软网站的 New Chinese Encoding GB-18030
http://www.microsoft.com/globaldev/drintl/columns/015/default.mspx?gssnb=1
计算机组成原理汉字编码与校验设计实验报告(汉字国标码转区位码实验、汉字机内码获取实验、海明编码电路设计与海明解码) 这次实验利用logisim进行设计,进行了以下这四个实验,其中分为汉字国标码转区位码实验、汉字机内码获取实验、海明编码电路设计与海明解码,实验报告分为四个部分,在这四个部分中依次对四个实验的方案设计,设计思路进行了介绍 阅读详情

相关推荐

汉明编码设计实验.zip

华中科技大学视频——汉明编码设计实验,里面包含有已写好的实验报告,data实验以及汉字转区位码的java代码。实验报告的内容是设计包含16位原始数据(汉字机内码)的汉明码等。望下载的小伙伴门记得自己修改自己想要的汉字区位码

汉字编码实验

在本实验中我学会了汉字编码的转换,国标转区位码的电路设计等等。最初让我感到困惑的就是汉字编码的一些概念,对机内码和国标码的理解还不到位导致后面设计困难。

ntr851217的博客 3406

汉字编码问题总结

gb,unicode,big5三种可能的汉字编码总结

华中科技大学计算机组成原理实验——数据表达实验

一、实验目的 1.理解汉字机内码、区位码的概念,并且能够利用相关的工具批量获取一段汉字文字的GB2312机内码,利用简单的电路实现汉字GB2312机内码与区位码的转换; 2.了解字形码显示的基本原理,能够在实验环境中实现汉字GB2312编码的字形码点阵显示; 3.掌握CRC校验码设计原理与纠错性能,能单独设计实现16位汉字GB2312机内码的CRC编码体系,并最终在实验环境中利用硬件电路实现对应的CRC编码和解码电路; 4.熟悉流水传输机制、流水暂停原理,能够对实验环境提供的五段流水编码传输电

weixin_63870922的博客 7943

汉字的编码|ASCII|GBK|Unicode|UTF-8详解

字符集:是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。字符编码:在符号集合与二进制之间建立对应关系常用的字符集:ASCII字符集、GB2312字符集、BIG5字符集、GBK字符集、GB18030字符集、Unicode字符集等。

白帽阿叁的博客 3万+

计算机y应用基础,浅析计算机y应用基础知识123.ppt

浅析计算机y应用基础知识123ASCII代码表 代码:100 0001 = 65 表中高3位为000和001的两列是一些控制符。例如“NUM”表示空白、“STX”表示文本开始、“ETX”表示文本结束、“EOT”表示发送结束、“CR”表示回车、“CAN”表示作废、“SP”表示空格、“DEL”表示删除等。 在计算机中一个字节为8位,为了提高信息传输的可靠性,在ASCII码中把最高位(b8)...

weixin_39832829的博客 215

浅析字符编码

<br /><br />1. ASCII码<br />我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从0000000到11111111。<br />上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。<br /

闷骚的悟空 753

浅析Java程序员必知的中文字符编码知识

随着全球化的发展,中文在各种场景中的应用越来越广泛。而在Java开发中,中文字符编码问题也是一个常见且重要的问题。由于不同编码方式的差异,常常会出现中文乱码的问题,给程序的正确运行和开发造成影响。本文旨在浅析Java程序员必知的中文字符编码知识,包含 Java 中的字符编码概念,中文字符编码的问题,以及解决中文乱码问题的多种方法和实例演示。希望通过本文的介绍,读者们能够更加深入地了解中文字符编码,为 Java 程序的开发提供解决方案。

1041

Visual studio 与字符编码浅析

摘要:本文试图简单的说明Visual studio 2013 对于字符串编码的处理,和一些乱码问题的处理方法。关于字符编码1. 西方文字的编码。1.1 ASCII 码,ASCII是通用的英文字符的编码,对于英文字符,他采用7位2进制数来表示一个英文字符,我们知道1个byte包含8个bit,对于ASCII码来说,最高bit为0.1.2 ISO 8859,西方广泛使用的编码标准。用于西方文字,有256...

liangbch的专栏 5583

汉字编码原理

使用后台数据库先将所有汉字存起来使用时随机取出,这也是一种办法,但是中文汉字有这么多,怎么来制作呢?其实可以不使用任何后台数据库,使用程序就能做到这一切。要知道如何生成汉字,就得先了解中文汉字的编码原理。

Python之encode与decode浅析

Python之encode与decode浅析在 python 源代码文件中,如果你有用到非ASCII字符,则需要在文件头部进行字符编码的声明,声明如下:# code:UTF-8因为python 只检查 #、coding 和编码字符串,为了美观等原因可以如下写法:#-*-coding:utf-8-*-常见编码介绍:GB2312编码:适用于汉字处理、汉字通信等系统之间的信息交...

weixin_33858336的博客 144

浅析windows下字符集和文件编码存储/utf8/gbk

查看更多 windows下字符集和文件编码存储/utf8/gbk 1,字符集 这里主要讲两种字符集,DBCS和UCS DBCS即双字节编码字符集,最初的计算机只有ASCII码,发展至今,不能表示中文怎么办,于是中国人制定了GBK2312,以及后面陆续扩展并向下兼容的GBK,GB18030. Unicode学名是“Universal Multiple-Octet Coded Chasract...

Seanyxie Blog 1626

WEB前端 [编码] 规则浅析

前言 说到前端安全问题,首先想到的无疑是XSS(Cross Site Scripting,即跨站脚本),其主要发生在目标网站中目标用户的浏览器层面上,当用户浏览器渲染整个HTML文档的过程中出现了不被预期的脚本指令并执行时,XSS就会发生。XSS有三类: 反射型XSS:发出请求时,XSS代码出现在URL中,作为输入提交到服务端,服务端解析后响应,在响应内容中出现这段XSS代码,最...

weixin_30901729的博客 420

【算法浅析NO.00003】浅析base64编码算法的加密与解密:打造属于自己的“base64”! by arttnba3

【算法浅析NO.00003】浅析base64编码算法的加密与解密:打造属于自己的“base64”! by arttnba3绪论基本原理加密一、密钥64=2^6^(base64密钥)128=2^8^ (ASCII)二、转换规则:“三变四,按表转”重新分组时我们以每6个二进制位作为一组,共分为四组:最后在每组的高位补上两个0,变成标准的一个字节:三、非3倍数字节文本:“尾补0,余补=”对于多余的一个字...

arttnba3的博客 545
上一篇: n个数全排列的非递归生成算法,C实现
下一篇: C中动态二维数组的获取
hanbf
博客等级 码龄22年 8粉丝 9原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值