`
xygan
  • 浏览: 22800 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

文件编码入门:UTF-8和GB

阅读更多

移动比联通强?

在简体中文Windows系统中:

1.打开记事本,输入“移动”,保存关闭后重新打开,显示的仍然是“移动”两个字。

2.重新新建一个文本文件,输入“联通”,保存关闭后重新打开,显示的就不是“联通”字符了,而是看上去所谓的乱码。

的确,这就是一个编码问题。

编码问题由来

ASCII

字符需要编码,一套编码体系就形成了一个字符集。美国人最开始只创造了一个字符集,也就是ASCII字符集,ASCII字符集,长8位,首位为0。后来欧洲国家发现128个字符不够用,想利用ASCII128位,128位还是满足不了所有欧洲国家的要求,就对后128个字符进行分片,形成了iso-8859系列字符集,包括iso-8859-1iso-8859-2等。

GB2312GBKGB18030

计算机来到中国后,又催生了GB2312编码标准,GB2312没有包括繁体字,后又扩展成为GBKGB13000),GBKGB2312的“超集”。GB2312GBK编码标准中,存储方法兼容ASCII,汉字占用两个字节。2000年和2005年又发布了GB18030-2000GB18030-2005编码标准,存储方法中有单字节、双字节和四字节三种方式对字符编码进行存储。平时说的ANSI编码,都是根据不同的国家和地区而不同的标准。在简体中文系统下,ANSI 编码代表 GBK 编码,在日文操作系统下,ANSI 编码代表 JIS 编码。 不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。

Unicode

历史介绍省略数百字。。。

Unicode基于通用字符集(Universal Character Set)的标准来发展,是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。

 

UCS-2用两个字节编码, UCS-44个字节编码。UCS-4根据最高位为0的最高字节分成2^7=128group。每个group再根据次高字节分为256个平面(plane)。每个平面根据第3个字节分为256行 (row),每行有256个码位(cell)。group 0的平面0被称作BMPBasic Multilingual Plane)。将UCS-4BMP去掉前面的两个零字节就得到了UCS-2。每个平面有2^16=65536个码位。)

Unicode & GBXXX

UnicodeGBXXX是两套不同的编码标准,字符的码位不相同,如果需要转换,必须要同时知道一个字符在两个编码中的码位。

编码简介

UTF-8

Unicode是编码标准,并没有规定字符的存储方式。UTF-8UTF-16UTF-32都是将Unicode标准中的码位转换到具体存储数据的方案。总之,任何一个编码标准和具体的字符存储方案是分离的,只要存储后的编码还能映射到原始的编码标准中的码位。

为什么不直接用UnicodeUCS-2码位来直接当作字符存储的数据编码呢,一是为了考虑和ASCII的兼容性,二是对属于ASCII的字符用Unicode编码太占用空间。UTF-8就是在这样的情况下诞生了。UTF-8只是一种编码的存储方案,从一个字符的UTF-8编码可以找到唯一对应的Unicode码位。

简单介绍下UTF-8UTF-8以字节为单位对Unicode进行编码。从UnicodeUTF-8的编码方式如下:

 

  Unicode编码(16进制) ║ UTF-8 字节流(二进制)

  000000 - 00007F  ║ 0xxxxxxx

  000080 - 0007FF ║ 110xxxxx 10xxxxxx

  000800 - 00FFFF  ║ 1110xxxx 10xxxxxx 10xxxxxx

  010000 - 10FFFF  ║ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

 

UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。从上表可以看出,4字节模板有21x,即可以容纳21位二进制数字。Unicode的最大码位0x10FFFF也只有21位。

例:“汉”字的Unicode编码是0x6C490x6C490x0800-0xFFFF之间,使用用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89

判断一个文本编码是否是UTF-8编码的最简单的正则:

/^([\x01-\x7f]|[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/

上述正则并不是100%能够判断正确的。事实上也没有100%正确的方法。一个Bad Case就是文章开头提到的“联通”例子,“联通”的GBK编码是c1 aa cd a8,刚好符合了上述的正则表达式,被Windows记事本认为是UTF-8来编码了。

联通的Bad Case还不是最Bad的,假如c1 aa cd a8UTF-8编码,c1 aa对应到Unicode的十六进制表示是6A(字符j),只需要一个字节就可以表示了。所以c1 aa不是一个规范的UTF-8编码,虽然c1 aa可以通过简单的正则表达式验证。

下面是一个更BadCase,记事本输入“伞”,关闭后再打开,就变成拉丁字符ɡ了,对于这样一个文本文件,如果不额外告诉程序是什么编码的,程序当UTF-8和当GBK来处理都不是程序的错了。

那么哪些汉字会引起当作UTF-8来误读的情况呢?根据正则表达式和GBK的编码情况(全国信息技术标准化技术委员会汉字内码扩展规范(GBK)码:http://www.snwei.com/studypc/write/009.htm ),在[\xc0-\xdf][\x80-\xbf]之间的GBK编码的汉字都可能会有问题,只要GBK编码的文本文件中的字符都是落在这个范围内(包括有任意的其它ASCII字符的情况,比如“伞1”也会被当作UTF-8来处理),都会出现编码难以或者不能判断的情况。

UTF-8的编码就介绍到这儿,没有什么准确判断UTF-8编码的方法,isUTF8Encode这样的函数如果返回值是二值的,都是有例外的。到可以写个判断肯定不是UTF-8编码的方法。

BOM

BOM——Byte Order Mark,中文名译作“字节顺序标记”。在UCS 编码中有一个叫做 "Zero Width No-Break Space" ,中文译名作“零宽无间断间隔”的字符,它的编码是USC编码是FEFF。而FFFE 在 UCS 中是不存在的字符,所以不应该出现在实际传输中。UCS 规范建议我们在传输字节流前,先传输字符 "Zero Width No-Break Space"。这样如果接收者收到 FEFF,就表明这个字节流是 Big-Endian 的;如果收到FFFE,就表明这个字节流是 Little- Endian 的。因此字符 "Zero Width No-Break Space" (“零宽无间断间隔”)又被称作 BOM

UTF-8 不需要 BOM 来表明字节顺序,但可以用 BOM 来表明编码方式(不知道是不是MS干的)。字符 "Zero Width No-Break Space" 的 UTF-8 编码是 EF BB BF。所以如果接收者收到以 EF BB BF 开头的字节流,就知道这是 UTF-8编码了。Windows 就是使用 BOM 来标记文本文件的编码方式的。所以UTF-8一般有两种,一个是UTF-8 with BOM,一个是UTF-8 without BOMlinux下的非常多的程序都是不认UTF-8 with BOM的,另外PHP也是不认的,只要有BOMUTF-8PHP(最新版本是否支持BOM未验证)就会出错。

不过用BOM也会有Bad Case,“锘胯创”三个字在记事本中以GBK保存后再打开就变成了UTF-8的“贴”。不要在UTF-8中保存BOM头。如果在程序的输出中看到字符“锘”就要格外注意,很有可能是UTF-8 with BOM的编码被当作GBK的来处理了。

小结

个人认为GBK的主要优势在于Web页面和减少磁盘IOGBK能够节省实实在在的带宽,假设一个web请求可以省下100个字节,那么100/秒的访问下,能够节省100MB/s的带宽了。也许服务器可以支撑更大规模的请求访问,处理更多的数据,但是带宽不见得够用。

对于输入输出中有字符串的,最好都明确告知编码。程序自身内部的编码可以统一,而在输入输出的时候按要求进行转码。

 

参考文献

http://www.unicode.org/charts/ 

http://baike.baidu.com/view/40801.htm

http://www.hudong.com/wiki/gbk

分享到:
评论

相关推荐

    字符编码UTF8转GB2312+可批量转换+需安装Python

    该工具用于字符编码UTF8转GB2312,可批量转换。只需将该工具放置与需要转换文件的目录下,双击运行即可。 注意:需安装Python,Python 2和3 需安装通用编码检测器,文件内有安装方法; 该工具对于入门学习Python 也...

    字符编码GB2312转UTF8+可批量转换+需安装Python+学习Python参考

    该工具用于字符编码GB2312转UTF8,可批量转换。只需将该工具放置与需要转换文件的目录下,双击运行即可。 注意:需安装Python,Python 2和3 需安装通用编码检测器,文件内有安装方法; 该工具对于入门学习Python 也...

    Spring MVC 入门实例

    因为我的 jsp 和 html 文件都是 UTF-8 编码的, 所以我在 param-value 标签中设置了 UTF-8. 估计你使用的是 GB2312 或者 GBK, 立即转到 UTF-8 上来吧. 分解配置文件. context-param 标签指明我们的配置文件还有 /...

    彻底搞懂Python字符编码

    不论你是有着多年经验的 Python 老司机还是刚入门 Python 不久,你一定遇到过UnicodeEncodeError、UnicodeDecodeError 错误,每当遇到错误我们就拿着 encode、decode 函数翻来覆去的转换,有时试着试着问题就解决了...

    xml入门教程/xml入门教程

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <teacher xmlns="http://www.tarena.com/teacher" xmlns:student="http://www.tarena.com/student"> <name>zhangshan <sex>man <student:...

    wordpress入门到精通教程

    还有一种常用的编码是UTF-8编码,它是国际通用的编码。不管我们采用哪种编码,有一点就是包含的css样式表和其它文件也必须和本文档的编码一样,要不就会出现乱码。 3)html标签 成对的标签: <head>...</...

    新版Android开发教程.rar

    Android Android Android Android 开发入门 System System System System Requirements Requirements Requirements Requirements The sections below describe the system and software requirements for developing...

    125集专攻JAVA基础 JAVA零基础入门学习视频教程 动力节点JAVA视频教程.txt

    北京动力节点-Java编程零基础教程-055-Java基本语法-UTF-8的编码格式.avi 北京动力节点-Java编程零基础教程-056-Java基本语法-获取当前系统的字符编码.avi 北京动力节点-Java编程零基础教程-057-Java基本语法-...

    淘特站内搜索引擎(C#版)

    考虑到本软件使用的utf-8编码,某些语言如asp,php,有可能在get提交数据时使用的gb2312编码,如果不进行gb2312对utf-8的转换将会出现乱码现象,另外get方法提交数据也会有数据传输长度限制的问题,因此索引接口我们...

    XML轻松学习手册--XML肯定是未来的发展趋势,不论是网页设计师还是网络程序员,都应该及时学习和了解

     好了,通过第三章的学习,我们已经了解了一些XML和DTD的基本术语,但是我们还不知道怎样来写这些文件,需要遵循什么样的语法,在下一章,将重点介绍有关撰写XML和DTD文档的语法。 第四章 XML语法 七.DTD的语法...

    轻开平台(轻松互联网开发平台,原WebEasy)开发手册 20150915更新

    从基础知识、环境需求、系统安装、开发工具、开发规则到开发实例,由浅入深全面介绍轻开平台的Web和移动App(安卓、IOS)服务器开发过程,非职业程序员一周即能上手开发,有基础的程序员只需一天。...DriverName=...

Global site tag (gtag.js) - Google Analytics