`
xcy13638760
  • 浏览: 51536 次
社区版块
存档分类
最新评论

由web程序出现乱码开始挖掘(Bom头、字符集与乱码)

 
阅读更多

从第一次开始写web程序,自己还有身边同事开发出现乱码情况基本都没有消停过。估计以后还会一样继续。 这么些年,不断修修改改,也总结也归纳。程序从asp,asp.net,jsp,php,服务器从windows到linux,数据库也从sqlserver,mysql到oracle;它还是偶尔会出现。 好了,我总结下我与它较量的一些收获吧。乱码都与字符集有关系,一切都从它开始说。

  • 什么是字符集,什么是字符编码,它做什么用?

字符(Charcter)是文字与符号的总称,包括文字、图形符号、数学符号等。而字符集是一组抽象的字符组合的集合。如:英文字符集,中文字符集,日文字符集等

什么是字符编码?

计算机只能存储0,1之类2进制数字,怎么样让它表示那么多各种各样的字符呢?就需要对各种字符指定一个数值的编码代号它就是字符编码。如:a这个字符,在ascii字符集编码表中对应的编号是97,而“中”在gb2312字符集中对应的编号是:16进制是D6D0 10进制是54992 。通过编号就可以找到计算机对应字符。不用将那么复杂的字符保存在计算机中,只需要保存它代号就好。字符集只是指定了一个集合中有哪些字符,而字符编码,是为这个集合中所有字符定义个编号,这就是字符集与编码区别所在。

如果我告诉别人,我这个字符是:gb2312字符集中编号是:54992或者是D6D0 ,无论那个程序都知道是”中”,如果有人听错了,把它弄成日文JIS字符集,然后他也去找编号是:54992对应的字符,却找到的是:”面“。

打了这个比方,相信大家找到原因了,同样如果把54992拿到ascii 码表找,就会得到对应:�� 两个不能打印字符了。

从上面看,当你拿到本来是gb2312编号,在不是它的字符集里面找就出现这样问题了。 其它,程序出现乱码也都是这个原因,找错了字符集表了.

  • 字符在计算机是怎么样存储的呢?

看了上面介绍,我想大家一定会说,如果所有文本的字符,都用它的符号存储在计算机里面,不就什么问题都么有吗? 以前也这么想,后来一想啊,如果都存在计算机中,各种各样,怎么样表示呢?计算机处理01之类数字该多方便呢。

我们可以通过winhex实际来检查下,下面在简体中文下,将”中按照gb2312字符集编码保存。

image

以gb2312编码保存中文“中”,实际存储在计算机中是:D6D0,是“中”在字符集gb2312中的编号啦!

计算机中只保存字符在某字符集中对应的字符编号值,计算机只需要维持一份字符集清单,当读到这种编号值(编码),就在对应字符清单中找出该字符显示出来即可。字符大小颜色都是程序按照字符样式绘制而成的。

看个图:

image

计算机中只保存该字符在某字符集中对应的字符编号(也叫字符编码)

  • 怎么样读取文件并正确显示文件内容?

从上面例子知道字符实际以该字符在某字符集中字符编码存储与计算机磁盘中。

下面以“中国”为例(中文简体windows):

"中国" 保存编码 存储内容 记事本打开
ANSI D6D0 B9FA 正常
gb2312 D6D0 B9FA 正常
utf-8+BOM EFBBBF E4B8AD E59BBD 正常
utf-8 E4B8AD E59BBD 正常
unicode+BOM FFFE 2D4E FD56 正常
unicode 2D4E FD56 乱码(变成ANSI)
EUC-JP C3E6 B9F1 乱码(变成ANSI)
iso-8859-1 3F 3F 乱码(变成ANSI)

以下以:“abc”为例

"abc" 保存编码 存储内容 记事本打开
ANSI 61 62 63 正常
gb2312 61 62 63 正常
utf-8+BOM EFBBBF 61 62 63 正常
utf-8 61 62 63 正常
unicode+BOM FFFE 61 62 63 正常
unicode 61 62 63 正常(变成ANSI)
EUC-JP 61 62 63 正常(变成ANSI)
iso-8859-1 61 62 63 正常(变成ANSI)

从上面可以得到几点:

1、以某字符集存储字符时,它会在该字符集中搜索这个字符的位置(编号或编码),以这个编号(编码)保存在文件,如果所搜找不到该字符,一般会以:3F 3F保存(一定会出错)

2、当需要显示字符,从取文件中字符编码,如果没有指定字符集,会通过文件头(主要unicode字符集有特殊头标记)判断字符集,如果不是unicode字符集,默认都以ANSI字符集读取,用字符编码在该字符集中寻找对应字符,如果搜索到就正常显示,搜索不到就会显示乱码.

  • 常见问题字符疑问收集

什么是ANSI字符集?

这个不是固定字符集,如果在中文简体windows中,它代码字符集是gb2312,在繁体值代表是big5等等。

为什么英文字符不会出现乱码?

常见ascii码字符集是:128字符,对应编码值是:1-128 ,二进制表示是:00000001-01111111。它表示了所有常见英文数字,标点符号。其它字符集都是由ascii码字符集扩展而来,扩展了最高位由10000000开始,用多字节表示新的字符,基本都保留了:0xxxxxxx 开头128个基本字符,而且对应编码与ascii码相同。

这样,常见英文字符不论在那种字符集中,对应字符编码一致,存储编码也一样。读取时候无论用什么字符集读取,它所对应字符也一直。所有基本不会出现乱码情况。

读取软件能够识别存储文件的字符集吗?

由于目前各种字符集加起来有上百种,目前除了unicode字符集,定义的存储文件头,基本其它字符集只是给出了对应的字符编号值。因此,相同编号会出现在不同的字符集中,光从文件存储的编码值,是不能确定它的字符集的。如:gb2312字符集中,D6d0对应是“中”,而同样是:D6D0在ecu-jp 字符集中,对应是“面”

什么是bom头?

bom全称是:byte order mark,汉语意思是标记字节顺序码。只是出现在:unicode字符集中,只有unicode字符集,存储时候,要求指定编码,如果不指定,windows还会用默认的:ANSI读取。常见的bom头是:

  UTF-8 ║ EF BB BF 
  UTF-16LE ║ FF FE (小尾)
  UTF-16BE ║ FE FF (大尾)
  UTF-32LE ║ FF FE 00 00 
  UTF-32BE ║ 00 00 FE FF


unicode与utf-8 、utf-16 utf-32是什么关系?

unicode(统一码、万国码、单一码)是一种字符集,Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。在Unicode中:汉字“字”对应的数字是23383。我们可以用:UTF-8、UTF-16、UTF-32表示这个数字,将数字23383存储在计算机中。UTF-8对应是:0xE6, 0xB1, 0x89(3个字节),UTF-16对应是:0x6c49(2个字节),UTF-32对应是:0x6c49(4个字节)。utf-8,utf-16,utf-32是unicode码一种实现形式,都是属于unicode编码。

unicode编码特点是什么?

unicode编码特点是,它定义了编码方式和存储实现方式。编码方式就是上面说的可以用,utf-8…utf-32表示,而存储实现方式,无论那种编码都知道了文件头(bom)。因此,可以通过这个特殊头来判断存储的文本文件使用那种字符集编码。 
为什么utf-8编码不指定bom头(可以理解为文件头),软件任然可以正常判断出它字符集编码?
这个问题估计很多朋友都会产生疑问,为什么utf-16不指定就读乱码,而utf-8可以。我们可以从下面的例子看下: utf-8是怎么样从unicode转换而来了。

  Unicode编码(16进制) ║ UTF-8 字节流(二进制) 
  000000 - 00007F ║ 0xxxxxxx 
  000080 - 0007FF ║ 110xxxxx 10xxxxxx 
  000800 - 00FFFF ║ 1110xxxx 10xxxxxx 10xxxxxx 
  010000 - 10FFFF ║ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
从上面看,发现规律没有?第一个自己开头有几个”1”,后面就对应有几个10开头字节了。 这样我们都可以通过正则进行检测了.

[\x09\x0A\x0D\x20-\x7E] # ASCII
|[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|\xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
|\xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
|\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
|[\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
|\xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16

由于它独特的编码存储特点,因此目前常见文本处理软件就能够自动分析出来。(windows记事本,editplus,notepad++等)

为什么bom头会产生乱码?

有bom头的存储或者字节流,它一定是unicode字符集编码。到底属于那一种(utf-8还是utf-16或是utf-32),通过头可以判断出来。由于已经说过utf-16,utf-32不指定bom头,解析程序默认就认为是ansi编码,出现乱码。 而utf-8指定或者不指定程序都可判断知道对于的字符集编码。问题就出在这里,可能有的应用程序(ie6浏览器),它就认为如果utf-8编码,就不需要指定bom头,它可以自己判断,相反指定了bom头,它还会出现问题(因为它把头当utf-8解析出现乱码了)。这里不截图了,cnblogs里面谈这个比较多,目前ie6会出现问题。其它ie7+,firefox,chrome不会出现,会忽略掉bom头。 统一解决办法是:存为utf-8编码是,不需要加入bom头,其它utf-16,utf-32加入。

通过程序运算gb2312编码能够自动转换为utf-8编码吗?

utf-8实际是unicode字符集表现方式。如果看了这2种字符集编码表就清楚了。 它是2个独立字符集,相同汉字在2个字符集中所对应编号没有关系,而且汉字顺序也不同,gb2312先按照拼音后按照笔画排序,而unicode没有做相应规定。我们清楚知道,如果没有对应字符集映射关系表在手。通过直接程序进行运算是实现不了的。如果你手里有这2个字符集映射表。如:”字”utf-8是:0xE6, 0xB1, 0x89 ,对应unicode编码是:23383,然后拿23383,在unicode字符集寻找,发现是字符“字”,接着将“字”这个字符,拿到gb2312表中查询:0xCE,0xC4 因此转换结果是:0xE6,0xB1,0x89 ---> 0xCE,0xC4。

GB2312、GBK、gb18030、Big5是什么关系?

GB2312:1980年的GB2312一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。

GBK: 汉字国标扩展码,基本上采用了原来GB2312-80所有的汉字及码位,并涵盖了原Unicode中所有的汉字20902,总共收录了883个符号, 21003个汉字及提供了1894个造字码位。包括港、台两种汉字字库.

GB18030-2000产生,在GBK汉字标准字符集继续扩展,GB18030是GBK的超集,也就是包含的字符要比GBK多,又增加了6351个字符,其中一部分为4字节字(four-byte encoding range)。增加了六种少数民族语言和一些四字节字。

Big5是中国台湾的,是繁体中文代表

GB18030兼容GBK兼容GB2312 ,相同常用汉字在GB2312编码表中字符编号(编码)与GBK,GB18030相同。如:”字“gb2312字符编码是:0xCE,0xC4 ,它在其它2个里面也是这个。因为GB2312只有7000多常用汉字,当出现繁体,古文时候就会出现问题,因此采用大集合的GB18030是个不错选择。

Big5与GB2312不能通过程序相互转换,需要有字符集映射关系表才能完成。

字符集是怎么样一个演变过程呢?

这个如果讲故事可以讲很久了。当计算机有美国人发明后,当时设计到字符输入,由于是英文字符,通过收集整理。它们形成了标准的ascii码(128) 字符集。8位,首位为0。 由于不断普及,欧洲西方国家相应使用,发现有些特殊字符它们不能表示,如:λφ等。如是出来想法,想利用ascii码后128位,增加它们的字符。这样就出现了EASCII码。这些还是不能表示所有国家,想法语,俄语等有自己特殊字符。因此制定标准将后128位进行分片制定。制定出iso-8859系列字符集。

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 8859-8-I - 希伯来语(逻辑顺序)
ISO/IEC 8859-9(Latin-5 或 Turkish)- 它把Latin-1的冰岛语字母换走,加入土耳其语字母。
ISO/IEC 8859-10(Latin-6 或 Nordic)- 北日耳曼语支,用来代替Latin-4。
ISO/IEC 8859-11 (Thai) - 泰语,从泰国的 TIS620 标准字集演化而来。
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) - 东南欧语言。主要供罗马尼亚语使用,并加入欧元符号。

这些在一段时间,可以解决西方国家常见字符。当后来电脑在中日韩等国家普及时候,象中国常见汉字有7000多个,扩展128个空位,完全不够。因此,需要用多个字节表示。后来就定,第一个字节,第一位如果是1,后面还有一个字节与之一起表示一个字符。如果是0,就对应ascii码。 这样就形成了国内的gb2312,后来还是不够表示繁体中文,加入了:gbk,最后是gb18030,但是,这样全世界各个国家还是用它们自己字符集进行表示。没有一个统一的大字符集,能够表示全球所有字符。直到unicode出现,它的设计最多可以表示100多万个字符。全球所有字符都可以收纳在其中。 写出的程序,不用经常进行各种编码转换。就可以让世界上所有国家可以阅读对应字符文字。

什么是代码页,它与字符集有什么关系?

大家在指定网页程序语言生活,还记得cp936表示中文代码页(code page)。那么它与我们说的gbk字符集有什么关系呢?代码页是字符集编码的别名,也有人称"内码表"。早期,代码页是IBM称呼电脑BIOS本身支持的字符集编码的名称。

常见字符集与代码页直接映射是:

cp charset

932 — 日文
936 — 简体中文(GBK)
949 — 韩文
950 — 繁体中文(大五码)
1200 — UCS-2LE Unicode 小端序
1201 — UCS-2BE Unicode 大端序
65001 — UTF-8 Unicode

936就是我们的gbk字符编码集。

CJK字符集是什么?

cjk代号意思是:汉语(Chinese)、日语(Japanese)、韩语(Korean)。也就是包含这3国语言的字符集。包含这3个国家常见的汉字,一共有2万多个。

所有软件都会默认是:ANSI字符集吗?

不同程序默认读取字符集不同,上面举例是记事本默认是这样的。在php里面会以:iso-8859-1读取。 jsp程序,java默认字符集也是:iso-8859-1。

为什么很多软件程序编译过程使用是:iso-8859-1字符集?

由于我们通过应用程序书写的软件是用各种字符集编码保存在磁盘中。如果中文默认是用gbk。保存于磁盘中,默认以字节码保存,是否有无中文,每个字码值在:1-256。这些刚好可以用iso-8859-1扩展单字节字符集。因为,它是存储最小单元。在程序语言里面,不会用中文作变量,函数等名称。那些对应都是常见ascii码。而中文用字注释,或者一些常量中。在编译时候不会影响到语法问题。它会以原来字节码保持原样。在读取时候,只需要用对应的字符集编码读出,就能得到对应中文字符。

说到这里,其实字符集问题可能还有很多,欢迎讨论!

分享到:
评论

相关推荐

    中文版VS2008制作英文版安装程序出现乱码的解决方法

    VS2008在生成安装程序时,默认可能会使用中文字符集,例如GBK或GB2312,而这些字符集在英文系统中可能无法正确识别。为了解决这个问题,我们需要确保安装程序的资源文件和配置文件使用的是Unicode编码,这样在任何...

    java去掉txt文本的bom头信息

    在某些情况下,如读取或合并多个文本文件时,BOM头可能会导致不必要的困扰,例如乱码或解析错误。本文将详细介绍如何使用Java去除TXT文本文件的BOM头信息。 首先,我们需要理解BOM头的含义。BOM头是一个字节序列,...

    Java Web编程中页面跳转乱码问题的解决方案.pdf

    由于其可变长度特性,UTF-8编码对字符集的描述更为灵活,且不需要字节顺序标记(BOM)。 GBK编码主要应用于简体中文和繁体中文字符的表示,它兼容了BIG5编码内的所有汉字,并使用单字节和双字节的编码形式。GBK编码...

    layui分页表格及日期乱码.zip

    - 如果是数据库中的乱码,检查数据库的字符集设置,确保与应用程序使用的字符集一致。 5. 文件编码问题: 如果是"layui分页及表格提示乱码"的压缩包文件本身存在编码问题,尝试使用支持多种编码识别的工具打开,...

    c#汉字乱码处理

    编码是字符集与二进制数据之间的转换规则,不同的系统或软件可能默认使用不同的编码格式,如UTF-8、GBK(GB2312的扩展)、UTF-16等。 ### 1. 编码识别与设置 为了解决C#中汉字乱码的问题,关键在于正确识别文件的...

    Web_开发中遇到的UTF-8以及乱码的问题总结.zip

    在Web开发过程中,字符编码问题,尤其是UTF-8与乱码相关的困扰,是开发者经常会遇到的挑战。UTF-8是一种广泛使用的多字节字符编码,能够表示Unicode字符集中的几乎全部字符,从而使得不同语言和符号能在同一份文档中...

    韩文乱码转换器

    同时,对于开发人员来说,了解字符集的差异和如何在不同系统间进行编码转换也是必备技能。 总的来说,"韩文乱码转换器"是解决跨平台或跨系统韩文显示问题的有效工具,通过其强大的编码转换功能,可以确保韩语文本在...

    sql,GBK2312,UTF-8,UTF-8 无BOM,脚本字符集转换,脚本格式转换

    "sql,GBK2312,UTF-8,UTF-8 无BOM,脚本字符集转换,脚本格式转换"这个主题核心是关于如何在不同字符编码之间转换SQL脚本,以确保数据的正确性和兼容性。以下是一些相关的知识点: 1. **字符编码**:字符编码是...

    解决中文乱码问题专题

    3. 设置正确的字符集:在浏览器或其他应用中,确保设置的字符集与文件实际使用的编码相匹配。 4. 使用统一的编码标准:在项目开发中,建议全团队统一使用UTF-8编码,以避免编码不一致导致的问题。 三、预防中文...

    免费 java中文乱码字符集处理大全.docx

    Java采用Unicode作为内部编码,这使得在不同的操作系统或环境之间转移Java程序时可能出现乱码问题。 2. 中文操作系统如中文Windows 2000默认使用GBK或GB2312编码来处理和显示中文字符。当Java程序在这些系统上运行...

    flex php显示乱码解决

    - 确保在每个环节都采用UTF-8字符集,避免字符编码转换过程中出现乱码。 - 在保存PHP文件时,确保IDE的默认编码设置为UTF-8,避免因编辑器编码设置问题导致的数据错误。 - 对于MySQL,除了设置服务器级别的字符集外...

    解决VS2010复制汉字到Word出现乱码的小工具

    每种编码都有其特定的字符集和编码规则。 2. **Unicode**:是一种通用的字符编码标准,包含了世界上几乎所有的文字系统。VS2010通常使用UTF-8或UTF-16这两种Unicode变体进行编码。 3. **乱码**:当一个文本文件被用...

    批量转换字符集的小工具

    标题中的“批量转换字符集的小工具”指的是一个能够处理大量文件,将它们的字符编码从一种格式转换到另一种格式的应用程序。在IT领域,字符集转换是常见的需求,尤其是在处理不同地区、语言或平台的文本数据时。例如...

    jxl.jar原版、修改后的jxl.jar解决web dynpro中乱码问题

    【标题】"jxl.jar原版、修改后的jxl.jar解决web dynpro中乱码问题"涉及的关键技术点主要集中在两个方面:一是Java的jar包处理,二是Web Dynpro组件与Excel数据交互时的字符编码问题。下面将对这两个主题进行深入的...

    jsoncpp 写入乱码解决版本

    在JSONCPP中,可能会遇到写入文件时出现乱码的问题,这通常是由于编码不兼容或者字符集设置不当导致的。 在C++编程中,乱码问题通常涉及到字符编码,如ASCII、UTF-8、GBK等。JSON数据通常以UTF-8编码存储,因为它能...

    Java中字符集的详细介绍

    Java中的字符集是一个重要的概念,尤其对于处理多语言文本或者跨平台的数据交换至关重要。Java语言内部使用Unicode编码,具体来说是UTF-16格式,这意味着每个`char`类型变量能够表示一个Unicode字符,通常占据两个...

    C# mysql 插入数据,中文乱码的解决方法

    在使用C#与MySQL数据库进行交互时,遇到中文...通过在SQL语句前设置字符集或者在连接字符串中指定字符集,可以有效地避免中文乱码的问题。在实践中,选择第二种方法更为推荐,因为它更简洁且不会对其他操作产生副作用。

    网站开发中遇到UTF8出现乱码问题.docx

    总之,解决UTF-8乱码问题的关键在于确保整个系统(包括HTML、PHP、数据库、JavaScript以及Flash)的编码一致性,并注意处理好BOM、字符集声明和数据转换。在处理字符串截断、文件名和数据交互时,也需要特别注意UTF-...

    mysql乱码解决方法

    当从MySQL 4.1以下版本升级到4.1及以上版本时,可能会出现字符集兼容性问题,导致乱码。解决方法包括: - 确保所有数据库、表、字段的字符集设置为UTF-8。 - 如果是从非UTF-8编码的数据导入,需要先将数据文件...

    jsoncpp动态库(win32 relese版,解决toStyledString中文乱码问题)

    JSON是一种轻量级的数据交换格式,常用于Web服务与客户端之间的数据通信。JSONCPP库为C++开发者提供了一套易于使用的API,使得处理JSON数据变得更加便捷。 在标题中提到的“win32 relese版”,意味着这个版本的...

Global site tag (gtag.js) - Google Analytics