【13】编码、解码与乱码

编码、解码与乱码

一、常用字符集和编码

1.ASCII美国信息交换标准代码

  • 编码规则:7位表示一个字符,共128个字符

  • 缺点:只能显示26个拉丁字母、阿拉伯数字和英文标点符号

2.EASCII欧洲扩展字符集

  • 编码规则:8位表示一个字符,共256个字符

  • 缺点:虽解决了部分西欧语言的字符显示问题,但对其他更多的语言依然无力

3.GB2312/GB2312-80等中文字符集

  • 编码规则:把127号的字符取消掉(即EASCII),两个大于128的字符连在一起表示一个汉字,高字节从0xA1到0xF7,低字节从0xA1到0xFE

  • GBK中文字符集,微软对GB2312-80进行扩充后制定了GBK编码。

4.Unicode统一字符集

  • 包含超过十万个字符,让电脑能够解析世界上数十种语言。

  • 编码规则:使用4个字节的数字来表达字母、符号、文字。

  • Unicode指的是字符集,而UTF-32,UTF-16,UTF-8则说的是编码方案。

4.1 UTF-32

  • 编码规则:用上述Unicode的4字节的数字来表达字母、符号、文字

4.2 UTF-16

  • 编码规则:若字符编码U小于0x10000,也就是小于十进制的65535,则使用2个字节表示;

  • 若字符编码U大于0x10000,也就是大于十进制的65535,则使用4个字节表示。

4.3 UTF-8

  • 是针对对Unicode的可变长度字符编码,可表示Unicode中任何字符,且编码中第一个字节与ASCII兼容。

  • 编码规则是使用1到4个字节为每个字符编码:

  • 128个US-ASCII字符只需用1个字节编码,从U+0000到U+007F

  • 带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文等,则使用第2个字节编码,从U+0080到U+07FF

  • 其他基本多文中平面中的字符则使用3个字节编码

  • 其他极少辅助平面中的字符则使用4个字节编码

二、乱码问题详解

1.乱码产生的根本原因

  • 乱码产生的根本原因就是,数据的编码和解码所使用的码表不一致。

  • 数据编码后是以字节数组的形式保存在磁盘或者在网络中传输,当数据接收端不知道数据发送端所使用的码表时会使用本地定义的码表来解码。当两者不一致时,就有可能产生乱码!

  • 在上面的码表中,我们知道ISO8859-1、UTF-8、GBK等其实是对ASCII码表的扩展,所以保存在磁盘或者在网络中传输的ASCII码表中定义字符(26个拉丁字母、阿拉伯数字和英文标点符号)是不会出现乱码的。而中文字符,在ASCII码表和ISO8859-1中用一个字节是无法表示出来的,而在GBK中是用两个字节表示,在UTF-8是用三个字节表示,这种不同就是乱码的深层原因。

2.转码

一串用码表1编码的数据,被码表2解码后产生一串乱码,问如何获取可识别的内容?

1.将乱码用码表2重新编码成字节数组;

2.用码表1解码数据。即str=newString(str.getBytes(“码表2”),”码表1”);

3.URL编码

3.1 依据标准

2005年1月发布的RFC3986[1],强制所有新的URI必须对未保留字符不加以百分号编码;其它字符要先转换为UTF-8字节序列,然后对其字节值使用百分号编码。此前的URI不受此标准的影响;

3.2 URI的字符类型

URI所允许的字符分作保留与未保留。保留字符是那些具有特殊含义的字符.例如,斜线字符用于URL(或者更一般的,URI)不同部分的分界符.未保留字符没有这些特殊含义.百分号编码把保留字符表示为特殊字符序列。上述情形随URI与URI的不同版本规格会有轻微的变化。

  • RFC3986section2.2保留字符(2005年1月)
 ! * ' ( ) ; : @ & = + $ , / ? # [ ] 
  • RFC3986section2.3未保留字符(2005年1月)
 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z  
 a b c d e f g h i j k l m n o p q r s t u v w x y z 
 0 1 2 3 4 5 6 7 8 9 - _ . ~ 
  • URI中的其它字符必须用百分号编码。

3.3 URL编码和解码的过程

  1. 浏览器使用utf-8编码URL中的非未保留字符(包括保留字符和其他字符),得到一个字节数组,根据每个字节对应的十六进制表示用%隔开;

  2. 服务器收到数据,对其进行URL解码,解码依据是utf-8码表;

  3. 服务器用自身码表对其重新编码。

4.Servlet中的乱码问题

4.1 Request消息乱码

  • 如果没有指定封装Request对象的编码格式,Servlet默认使用ISO8859-1编码,会导致中文乱码;

  • 对于Request实体(来自POST请求)的内容,可以使用setCharacterEncoding(“utf-8”)指定编码的码表;

    //原码中的对该方法的解释
    Overrides the name of the character encoding used in the body of this request.
  • 对于Request头部(来自GET请求)的内容,不能通过setCharacterEncoding(“utf-8”)来解决乱码问题。只能通过转码newString(str.getBytes("iso8859-1"),"utf-8");或者使用URL解码URLDecoder.decode(“字符串”)的方式解决

4.2Response消息乱码

  • 如果没有指定封装Response对象的编码格式,Servlet默认使用ISO8859-1编码,会导致中文乱码;

  • 可以使用setCharacterEncoding(“utf-8”)来指定Servlet编码时使用UTF-8,但是这样做浏览器不知道该用什么码表来解码服务器的响应;

  • 使用setContentType(“text/html;charset=utf-8”)可以既可以指定Servlet编码是使用UTF-8,也可以告诉浏览器解码时使用UTF-8。

你可能感兴趣的:(编码,乱码,解码)