`
xygan
  • 浏览: 23173 次
  • 性别: 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 也...

    python:输出中文的开头编码

    由于Python源文件本身是按UTF-8编码的,所以处理中文字符不会出现太多问题,但为了确保Python脚本在不同环境和版本下都能正确处理中文字符,最好在文件的开头声明编码。 对于初学者,了解如何在Python脚本中输出...

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

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

    Java中的字符集编码入门(五)Java代码中的字符编码转换Part1.doc

    - **简化操作**:如果允许多种编码共存,则即使是简单的字符串操作也会变得复杂,比如连接一个GB2312编码的字符串和一个UTF-8编码的字符串时,很难确定最终结果应采用哪种编码。 - **确保一致性**:统一编码格式...

    UTF网页汉字编码到国标码.zip易语言项目例子源码下载

    1. 读取UTF-8编码的网页内容:可以使用易语言的文件操作命令,如“读文本文件”或“读网络文件”,获取网页的UTF-8编码字符串。 2. 分析UTF-8编码:UTF-8编码的特点是首位标识字节的最高位,根据这些位可以确定字符...

    大学计算机基础 6-11章课件

    - 字符编码:ASCII码、Unicode(UTF-8)及汉字编码。 - 浮点数表示:IEEE 754标准。 - 存储单位:字节、KB、MB、GB、TB等。 3. **第八章:操作系统基础**: - 操作系统定义与功能:进程管理、内存管理、文件...

    Sphinx 在 windows 下安装使用.docx

    - 支持单字节编码和UTF-8编码。 - 原生支持MySQL和PostgreSQL。 2. **Sphinx在Windows上的安装步骤**: - 访问官方网站下载最新Windows版本,如Win32 release binaries with MySQL support。 - 解压缩到指定...

    Qt初学者学习文档,讲述了基础用法和常用控件

    - 对于Qt5.0以下版本,在`main.cpp`中修改编码方式为UTF-8: ```cpp #include int main(int argc, char *argv[]) { QApplication a(argc, argv); QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8...

    linux 操作系统暗转使用说明

    在某些情况下,Qt Creator可能会报告无法识别文件编码为UTF-8的问题。此时,可以通过以下方式解决: 1. 打开Qt Creator中的文件。 2. 在文件菜单下选择“重新加载”。 3. 选择GB2312编码格式。 4. 修改`main.cpp`...

    pilotedit大文本文件编辑器

    - **编码转换:**支持多种字符编码,包括ASCII、Unicode、UTF-8等,方便跨平台和跨编码格式的工作。 - **行号显示与书签:**显示行号以便于定位,设置书签则可以快速跳转到重要位置。 2. **高级编程与开发辅助:*...

    Spring MVC 入门实例

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

    Java入门学习笔记2019年4月

    - 主要编码标准: GB2312, UTF-8, UTF-16, UTF-32 - Unicode 码: 一种广泛使用的字符编码标准, 能够覆盖几乎所有语言的文字 **5. 运算符** - **算术运算符**: `+`, `-`, `*`, `/`, `%` - **自增减运算符**: `++`, `-...

    TinyXML入门教程

    - 注意:如果文档使用的是UTF-8编码,在Windows环境下输出可能会出现乱码问题,因为默认控制台编码为gb2312。 - **保存文档对象**: - `TiXmlDocument`还提供了`SaveFile`方法用于保存文档到新的文件。 ```cpp ...

    Python基础入门教程 由浅入深讲解清晰 第4章 字符串与正则表达式 (共55页).ppt

    随着信息技术的发展,为了容纳更多国家的文字,出现了多种编码格式,如UTF-8、GB2312、GBK和CP936等。 - **UTF-8** 是一种可变长度的编码,可以表示全世界所有国家的字符,它使用1到4个字节来编码一个字符,英文...

    jquery14.1chm、jquery1.3.2vs2008中文版智能提示

    **字符编码:UTF-8和GBK** 在处理文本文件时,字符编码是个关键问题。"UTF-8"是一种广泛使用的Unicode编码,支持世界上几乎所有的字符集,包括中文。"GBK"是中国大陆的国家标准,是对GB2312的扩展,也包含了大量...

    易语言源码易语言取GB2312汉字源码.rar

    3. 编码转换:在不同环境下,可能需要将GB2312编码转换为其他编码格式,如UTF-8,以便在不同的系统或软件间兼容。易语言提供了转换编码的函数,可以实现不同编码间的转换。 4. 错误处理:在处理汉字编码时,可能会...

    廖雪峰Python入门资料整理(共67页非常简单已入门者误下)

    例如,可以将Unicode字符串转换为UTF-8或GB2312编码的字节序列。 - **`decode()`**:将字节序列转换回字符串。此过程可能会遇到无法解码的字节,可以通过设置`errors`参数来处理这些情况,如`errors='ignore'`忽略...

    python学习教程【含15个综合练习】

    - Python中,二进制(0/1)可以转换为ASCII,进一步转换为各种字符编码,如GB2312、GBK、GB18030,最通用的是Unicode,最终以UTF-8编码存储和传输。 - `chr()` 和 `ord()` 函数分别用于将二进制转换为字符和字符...

    贡献百度的代码源详解

    - 示例代码中的某些属性(如`<meta http-equiv="Content-Type">`中的`gb2312`字符集)已经不再推荐使用,建议采用UTF-8编码。 - 在实际项目中,还需要关注浏览器兼容性问题,确保网站能够在不同的浏览器和设备上...

Global site tag (gtag.js) - Google Analytics