• zz乱码、编码问题详


    http://developerblog.org/?p=232

    因为电脑是windows 7系统,开发环境又在linux,经常在linux碰到乱码问题,很是痛苦,于是决定好好了解编码的来龙气脉,并分享个各位,免得出现乱码时不知所措。

    是否存在文件编码

    在讲解字符编码之前,我们需先明确文件本身没有编码一说,只有文字才有编码的概念,我们通常说某个文件是什么编码,通常是指文件里字符的编码。

    为什么会出现乱码

    我在linux下一般使用vim进行文件编辑,发现经常会碰到乱码的情况,那么为什么会出现乱码呢?

    首先我们了解下vim编码方面的基础知识,关于编码方面vim存在3个变量:
    1.encoding: Vim 内部使用的字符编码方式,包括 Vim 的 buffer (缓冲区)、菜单文本、消息文本等。默认是根据你的locale选择.用户手册上建议只在 .vimrc 中改变它的值,事实上似乎也只有在.vimrc 中改变它的值才有意义。你可以用另外一种编码来编辑和保存文件,如你的vim的encoding为utf-8,所编辑的文件采用cp936编码,vim会自动将读入的文件转成utf-8(vim的能读懂的方式),而当你写入文件时,又会自动转回成cp936(文件的保存编码).

    2.fileencoding: Vim 中当前编辑的文件的字符编码方式,Vim 保存文件时也会将文件保存为这种字符编码方式 (不管是否新文件都如此)。

    3.termencoding: Vim 所工作的终端 (或者 Windows 的 Console 窗口) 的字符编码方式。如果vim所在的term与vim编码相同,则无需设置。如其不然,你可以用vim的termencoding选项将自动转换成term的编码.
    当这三个变量的编码出现问题时就会出现乱码。

    1.encoding不是utf-8编码

    如果encoding不是utf-8编码,其他字符可能无法转为

    Encoding的指定编码。如:如果encoding是gbk编码,而文件内容采用big5编码的,其就无法转换为gbk编码。

    2.fileencoding不对。

    Fileencoding编码是vim的读取文件内容时使用的编码,如果其编码与文件字符编码不同,必然会出现乱码。Fileencoding编码一般由vim自动检测,可以使用fileencodings设置 Vim自动探测fileencoding的顺序列表。不过vim有时候会检测错误,就会出现乱码了。

    3.termencoding编码不对。

    我们登录服务器一般采用远程登录,这就涉及终端编码问题,我经常碰到因为终端编码不对导致乱码的。如:SecureCRT设置为utf-8编码,而vim的termencoding却为gbk,就出现乱码了。

    字符编码介绍

    说了那么多,到底字符编码是什么玩意呢?

    字符(Character)是文字与符号的总称,包括文字、图形符号、数学符号等,一组抽象字符的集合就是字符集(Charset)。
    字符集常常和一种具体的语言文字对应起来,该文字中的所有字符或者大部分常用字符就构成了该文字的字符集,比如英文字符集,汉字字符集。
    计算机要处理各种字符,就需要将字符和二进制内码对应起来,这种对应关系就是字符编码(Encoding)。
    制定编码首先要确定字符集,并将字符集内的字符排序,然后和二进制数字对应起来。根据字符集内字符的多少,会确定用几个字节来编码。

    字符编码的发展

    字符编码大概分为三个发展阶段。

    ASCII编码

    ASCII(American Standard Code for Information Interchange,美国信息互换标准代码)是基于拉丁字母的一套电脑编码系统。

    因为计算机起源于美国,为表示英文字符,他们制定了ASCII编码,ASCII编码使用7位二进制来表示字符,高位用来做奇偶校验,0×20以下的字节状态称为”控制码”,同时包括标点符号、数字等,当时人们觉得已经够用了。

    但随着计算机的广泛应用,别的国家也开始使用计算机,但是很多国家用的不是英文,他们的字母里有许多是ASCII里没有的,为了可以在计算机保存他们的文字,他们决定采用127号之后的空位来表示这些新的字母、符号,还加入了很多画表格时需要用下到的横线、竖线、交叉等形状,一直把序号编到了最后一个状态255。从128到255这一页的字符集被称”扩展字符集”。最优秀的扩展方案是ISO 8859-1,通常称之为Latin-1。Latin-1包括了足够的附加字符集来写基本的西欧语言。

    ANSI编码

    为使计算机支持更多语言,不同的国家和地区制定了不同的标准,产生了GB2312,BIG5,JIS等各自的编码标准。通常使用0×80~xFF范围的2个字节来表示1个字符。比如:汉字 ‘中’ 在中文操作系统中,使用 [0xD6,0xD0]这两个字节存储。

    由此这些使用2个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。

    Unicode编码

    由于不同国家的ANSI编码互不兼容,为了使国际间信息交流更加方便,国际组织制定了 UNICODE 字符集,为各种语言中的每一个字符设定了统一并且唯一的数字编号,以满足跨语言、跨平台进行文本转换、处理的要求。

    UNICODE开始制订时,计算机的存储器容量极大地发展了,空间再也不成为问题了。于是ISO就直接规定必须用两个字节,也就是16位来统一表示所有的字符,对于ascii里的那些“半角”字符,UNICODE保持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间。

    但是UNICODE来到时,一起到来的还有计算机网络的兴起,UNICODE如何在网络上传输也是一个必须考虑的问题,于是面向传输的众UTF(UCS Transfer Format)标准出现了,顾名思义,UTF8就是每次8个位传输数据,而UTF16就是每次16个位,只不过为了传输时的可靠性,从UNICODE到UTF时并不是直接的对应,而是要过一些算法和规则来转换。
    学过计算机网络的童鞋都知道,在网络里传递信息时有一个很重要的问题,就是对于数据高低位的解读方式,一些计算机是采用低位先发送的方法,例如我们PC机采用的INTEL架构,而另一些是采用高位先发送的方式,在网络中交换数据时,为了核对双方对于高低位的认识是否是一致的,采用了一种很简便的方法,就是在文本流的开始时向对方发送一个标志符——如果之后的文本是高位在位,那就发送”FEFF”,反之,则发送”FFFE”。

    因为UTF-8编码兼容之前的ASCII编码,而且有利于传输,其得到了非常广泛的应用。

    从UNICODE到UTF8的转换规则:
    Unicode
    UTF-8

    0000 - 007F
    0xxxxxxx

    0080 - 07FF
    110xxxxx 10xxxxxx

    0800 - FFFF
    1110xxxx 10xxxxxx 10xxxxxx

    汉字ANSI编码发展

    GB2312

    为了表示汉字,我们国家首先发明了GB2312 编码,GB2312 编码规定一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。

    GBK

    后来发现很多偏僻字和少数名族的语言还是没办法编码进来,为了表示这些字符,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK包括了GB2312的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。

    GB18030
    后来少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK扩成了GB18030。从此之后,中华民族的文化就可以在计算机时代中传承了。

    BOM介绍

    1.BOM的来历

    为了识别 Unicode 文件,Microsoft 建议所有的 Unicode 文件应该以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字符开头。这作为一个“特征符”或“字节顺序标记(byte-order mark,BOM)”来识别文件中使用的编码和字节顺序。

    2.不同的系统对BOM的支持

    因为一些系统或程序不支持BOM,因此带有BOM的Unicode文件有时会带来一些问题。

    ①JDK1.5以及之前的Reader都不能处理带有BOM的UTF-8编码的文件,解析这种格式的xml文件时,会抛出异常:Content is not allowed in prolog。

    ②Linux/UNIX 并没有使用 BOM,因为它会破坏现有的 ASCII 文件的语法约定。

    ③不同的编辑工具对BOM的处理也各不相同。使用Windows自带的记事本将文件保存为UTF-8编码的时候,记事本会自动在文件开头插入BOM(虽然BOM对UTF-8来说并不是必须的)。而其它很多编辑器用不用BOM是可以选择的。UTF-8、UTF-16都是如此。

    3.BOM与XML

    XML解析读取XML文档时,W3C定义了3条规则:

    ①如果文档中有BOM,就定义了文件编码;

    ②如果文档中没有BOM,就查看XML声明中的编码属性;

    ③如果上述两者都没有,就假定XML文档采用UTF-8编码。

    决定文本的字符集与编码

    软件通常有三种途径来决定文本的字符集和编码。

    1.对于Unicode文本最标准的途径是检测文本最开头的几个字节。如:

    开头字节      Charset/encoding

    EF BB BF    UTF-8

    FE FF     UTF-16/UCS-2, little endian(UTF-16LE)

    FF FE     UTF-16/UCS-2, big endian(UTF-16BE)

    FF FE 00 00  UTF-32/UCS-4, little endian.

    00 00 FE FF  UTF-32/UCS-4, big-endia

    2.采取一种比较安全的方式来决定字符集及其编码,那就是弹出一个对话框来请示用户

    然而MBCS文本(ANSI)没有这些位于开头的字符集标记,现在很多软件保存文本为Unicode时,可以选择是否保存这些位于开头的字符集标记。因此,软件不应该依赖于这种途径。这时,软件可以采取一种比较安全的方式来决定字符集及其编码,那就是弹出一个对话框来请示用户。

    3.采取自己“猜”的方法。

    如果软件不想麻烦用户,或者它不方便向用户请示,那它只能采取自己“猜”的方法,软件可以根据整个文本的特征来猜测它可能属于哪个charset,这就很可能不准了。使用记事本打开那个“联通”文件就属于这种情况。(把原本属于ANSI编码的文件当成UTF-8处理,详细说明见:http://blog.csdn.net/omohe/archive/2007/05/29/1630186.aspx)

    记事本的几种编码介绍

    1.ANSI编码

    记事本默认保存的编码格式是:ANSI,即本地操作系统默认的内码,简体中文一般为GB2312。这个怎么验证呢?用记事本保存后,使用EmEditor、EditPlus和UltraEdit之类的文本编辑器打开。推荐使用EmEditor,打开后,在又下角会显示编码:GB2312。

    2.Unicode编码

    用记事本另存为时,编码选择“Unicode”,用EmEditor打开该文件,发现编码格式是:UTF-16LE+BOM(有签名)。用十六进制方式查看,发现开头两字节为:FF FE。这就是BOM。

    3.Unicode big endian

    用记事本另存为时,编码选择“Unicode”,用EmEditor打开该文件,发现编码格式是:UTF-16BE+BOM(有签名)。用十六进制方式查看,发现开头两字节为:FE FF。这就是BOM。

    4.UTF-8

    用记事本另存为时,编码选择“UTF-8”,用EmEditor打开该文件,发现编码格式是:UTF-8(有签名)。用十六进制方式查看,发现开头三个字节为:EF BB BF。这就是BOM。

    参考文档:

    1.  http://polaris.blog.51cto.com/1146394/377468

    2.  http://blog.csdn.net/omohe/article/details/1630186

  • 相关阅读:
    【Java】推断文件的后缀名
    UVa 131
    Java开发手冊 Java学习手冊教程(MtJava开发手冊)
    《Java并发编程实战》第十五章 原子变量与非堵塞同步机制 读书笔记
    OC语言--NSFileManager& NSFileHandle
    为什么我刚发表的文章变成了“待审核”,csdn有没有官方解释啊
    mac os升级为 Yosemite 10.10 后不能创建javaproject
    【spring】在spring cloud项目中使用@ControllerAdvice做自定义异常拦截,无效 解决原因
    【mybatis】mybatis动态order by 的问题, 注意 只需要把#{} 改成 ${} 即可
    【spring cloud】一个ms微服务想要给注册中心eureka发现,需要满足这些条件,微服务不能被eureka注册中心发现的解决方案
  • 原文地址:https://www.cnblogs.com/Akagi201/p/2480109.html
Copyright © 2020-2023  润新知