在编程过程中,字符的编码问题不可避免。以Web应用为例,HTTP协议中报文头里的Accept-Charset、Accept-Encoding、Content-Encoding等就是字符编码的一种体现。当我们充分理解字符编码的原理后,我们就可以避免再看到诸如??OY}T??N*NuL?乱码的情况。

基本概念

编码:把一种信息格式转换为另一种信息格式。对与计算机而言,此过程是把我们自然世界里的字符、声频、音频等转换为二进制形式。
解码:编码的逆过程。
乱码:不能正确显示字符的现象,原因多是编码与解码所用的映射关系不匹配。
字符集:某一系统所有字符的集合。如:中文字符集包括汉字、汉字符号等。
字符编码:把字符集中的字符编码成指定集合中的对象。如Unicode编码、GB2312字符编码。通常,人们认为字符集和字符编码是同义词(因为特定的字符编码会有唯一的字符集与之对应)。

各国编码

了解了编码的基本概念之后,我们需要明确一下,各国是如何对本国字符进行编码的:
ASCII编码
由于计算机是西方国家产物。因此,在计算机被发明的很长时间内,都是使用一种叫ASCII码的东西对西方国家常用的字符进行编码。
ASCII使用一个字节存储字符,且第一位同一为0,实际只能表示128个字符。对应的码表可以在这个网站查看。
各国独立编码
虽然ASCII对于美国等西方国家使用时勉强足够,但是对非英语系的国家而言,其字符远远不知128个,因此,各国纷纷拟定能够容纳本国字符的编码。比方中国的GB2312编码、日本的ISO2022编码。
Unicode编码
各国使用各自的编码,在本国使用当然不会有问题。如果编码的对象需要在互联网上传输、共享,还是会有乱码的发生。因此,一个怀着「把世界上所有的字符都用同一编码」伟大梦想的,统一码联盟诞生了。这个联盟拟定的编码方式如:UTF-32(使用4个字节存储一个字符);UTF-16(使用2个字节存储一个字符);UTF-8(使用1-4个字节变长编码)等实现。
UTF-8编码
我们知道UTF-8编码只是Unicode编码的一种实现,但在编程中,UTF-8也是最经常使用的。因此,这里简单介绍一下UTF-8的编码策略。
对于UTF-8编码的字符,第一个字节里的高x位1表示该字符用x位字节编码;接下来的x位前两位必是10。下面的表格简单模拟了UTF-8编码过程:

码点位数 码点起值 码点终值 字节序列 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6
7 U+0000 U+007F 1 0xxxxxxx NULL NULL NULL NULL NULL
11 U+0080 U+07FF 2 110xxxxx 10xxxxxx NULL NULL NULL NULL
16 U+0080 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx NULL NULL NULL
21 U+10000 U+1FFFFF 4 11110xxx 10xxxxx 10xxxxxx 10xxxxxx NULL NULL
26 U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx NULL
31 U+4000000 U+7FFFFFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

由上面的表格可以看出,当高1位为0时,UTF-8编码和ASCII编码一致。

编码应用

在JEE开发过程中,假定有如下JSP页面:

<%@ page pageEncoding="UTF-8" contentType="text/html;charset=UTF-8"%>
<%
    out.print("中国");
%>

在这里:

  • pageEncoding:JSP转换成Servlet时使用的编码

  • contentType:获取printWriter时,使用的编码

两者使用的映射一样,不会出现乱码。

参考文献

维基百科|字符编码
维基百科|UTF-8


野原英雄
206 声望25 粉丝

一只小猿


引用和评论

0 条评论