尚学堂.张志宇.乱码分析_01_基础.doc

1. 什么是ASCII码
ASCII(American Standard Code for Information Interchange,美国信息互换标准代码)
ASCII码一共规定了128个字符的编码
ASCII 表上的数字 0–31 分配给了控制字符,用于控制像打印机等一些外围设备。
它已被国际标准化组织(ISO)定为国际标准,称为ISO 646标准。

参考:
从这里看ASCII的内容
http://www.jimprice.com/jim-asc.shtml
或者看这张图来了解ASCII的内容
http://www.asciitable.com/
控制字符都什么含义,可以从这个网址了解
http://zh.wikipedia.org/w/index.php?title=ASCII&variant=zh-cn


2. 什么是ISO/IEC iso8859
ISO 8859,全称ISO/IEC 8859,是国际标准化组织(ISO)及国际电工委员会(IEC)联合制定的一系列8位字符集的标准,现时定义了15个字符集。
 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) - 东南欧语言。主要供罗马尼亚语使用,并加入欧元符号。
参考:
这里有比较详细的说明
http://zh.wikipedia.org/w/index.php?title=ISO/IEC_8859&variant=zh-cn

3. ISO/IEC 8859十五个字符集的比较
参考
http://zh.wikipedia.org/w/index.php?title=ISO/IEC_8859&variant=zh-cn
或者看这个也行
http://www.terena.org/activities/multiling/ml-docs/iso-8859.html

4. 什么是iso-8859-1
在ISO/IEC 8859-n之中,国际标准化组织只替每个字符集定义了最多96个字符(0xA0-0xFF)。

ISO-8859-n(在ISO与8859之间加上一连字号)则是由IANA根据ISO/IEC 8859-n所定义的编码表。它除了ISO/IEC 8859-n的字符外,还包括ASCII(0x20-0x7E)字符及65个控制字符(0x00-0x1F及0x7E-0x9F)。

参考:
http://zh.wikipedia.org/wiki/ISO/IEC_8859-1
http://wiki.ccw.com.cn/ISO_8859-1


5. 什么是unicode
Unicode 的编码方式与 ISO 10646 的通用字符集(Universal Character Set,UCS)概念相对应,目前实际应用的 Unicode 版本对应于 UCS-2,使用16位的编码空间。也就是每个字符占用2个字节。

参考:
中文的说明
http://zh.wikipedia.org/w/index.php?title=Unicode&variant=zh-cn

官方网址
http://www.unicode.org/
如果想下载编码具体内容
http://www.unicode.org/charts/
查看各种字符集的对应关系
http://www.unicode.org/Public/MAPPINGS/

完整Unicode编码表
http://zh.wikibooks.org/wiki/Unicode

6. 增补字符

增补字符是 Unicode 标准中代码点超出 U+FFFF 的字符
增补字符是代码点在 U+10000 至 U+10FFFF 范围之间的字符,也就是那些使用原始的 Unicode 的 16 位设计无法表示的字符

在UTF-16编码中,增补字符表示成两个字节。第一个字节属于高代理范围(\uD800-\uDBFF), 第二个字节属于低代理范围 (\uDC00-\uDFFF).

package encodetest;

public class TestChar {
public static void main(String[] args) {
System.out.println(Character.charCount(0x10000));
System.out.println(Character.isHighSurrogate((char)0xd87e));
System.out.println(Character.isLowSurrogate((char)0xdc1a));
String s=String.valueOf(Character.toChars(0x2F81A));
char[]chars=s.toCharArray();
for(char c:chars){
    System.out.format("%x",(short)c);
}
//d87edc1a
//这个字符变成了两个char型变量,其中0xd87e就是高代理部分的值,0xdc1a就是低代理的值。
}
}

参考
Java 平台中的增补字符
http://gceclub.sun.com.cn/developer/technicalArticles/Intl/Supplementary/index_zh_CN.html

7. Big Endian和Little Endian
一个字符可能占用多个字节,那么这多个字节在计算机中如何存储呢?比如字符0xabcd,它的存储格式到底是 AB CD,还是 CD AB 呢?
实际上两者都有可能,并分别有不同的名字。如果存储为 AB CD,则称为Big Endian;如果存储为 CD AB,则称为Little Endian。

8. ISO/IEC 8859-1:1998 与Unicode的关系
http://www.unicode.org/Public/MAPPINGS/ISO8859/8859-1.TXT
9. ASCII与Unicode的关系
http://www.unicode.org/Public/MAPPINGS/VENDORS/MISC/US-ASCII-QUOTES.TXT
10. UCS-2和UCS-4
 Unicode是为整合全世界的所有语言文字而诞生的。任何文字在Unicode中都对应一个值,这个值称为代码点(code point)。代码点的值通常写成 U+ABCD 的格式。而文字和代码点之间的对应关系就是UCS-2(Universal Character Set coded in 2 octets)。顾名思义,UCS-2是用两个字节来表示代码点,其取值范围为 U+0000~U+FFFF。
 为了能表示更多的文字,人们又提出了UCS-4,即用四个字节表示代码点。它的范围为 U+00000000~U+7FFFFFFF,其中 U+00000000~U+0000FFFF和UCS-2是一样的。
 要注意,UCS-2和UCS-4只规定了代码点和文字之间的对应关系,并没有规定代码点在计算机中如何存储。规定存储方式的称为UTF(Unicode Transformation Format),其中应用较多的就是UTF-16和UTF-8了。
11. UTF-16

 UTF-16由RFC2781规定,它使用两个字节来表示一个代码点。
 不难猜到,UTF-16是完全对应于UCS-2的,即把UCS-2规定的代码点通过Big Endian或Little Endian方式直接保存下来。UTF-16包括三种:UTF-16,UTF-16BE(Big Endian),UTF-16LE(Little Endian)。
 UTF-16BE和UTF-16LE不难理解,而UTF-16就需要通过在文件开头以名为BOM(Byte Order Mark)的字符来表明文件是Big Endian还是Little Endian。BOM为U+FEFF这个字符。
 其实BOM是个小聪明的想法。由于UCS-2没有定义U+FFFE,因此只要出现 FF FE 或者 FE FF 这样的字节序列,就可以认为它是U+FEFF,并且可以判断出是Big Endian还是Little Endian。
 举个例子。“ABC”这三个字符用各种方式编码后的结果如下:
UTF-16BE 00 41 00 42 00 43
UTF-16LE 41 00 42 00 43 00
UTF-16(Big Endian) FE FF 00 41 00 42 00 43
UTF-16(Little Endian) FF FE 41 00 42 00 43 00
UTF-16(不带BOM) 00 41 00 42 00 43
 Windows平台下默认的Unicode编码为Little Endian的UTF-16(即上述的 FF FE 41 00 42 00 43 00)。你可以打开记事本,写上ABC,然后保存,再用二进制编辑器看看它的编码结果。

 另外,UTF-16还能表示一部分的UCS-4代码点——U+10000~U+10FFFF。表示算法比较复杂,简单说明如下:
 从代码点U中减去0x10000,得到U'。这样U+10000~U+10FFFF就变成了 0x00000~0xFFFFF。
 用20位二进制数表示U'。 U'=yyyyyyyyyyxxxxxxxxxx
 将前10位和后10位用W1和W2表示,W1=110110yyyyyyyyyy,W2=110111xxxxxxxxxx,则 W1 = D800~DBFF,W2 = DC00~DFFF。
 例如,U+12345表示为 D8 08 DF 45(UTF-16BE),或者08 D8 45 DF(UTF-16LE)。
 但是由于这种算法的存在,造成UCS-2中的 U+D800~U+DFFF 变成了无定义的字符。

参考:http://www.ietf.org/rfc/rfc2781.txt
12. UTF-32
UTF-32用四个字节表示代码点,这样就可以完全表示UCS-4的所有代码点,而无需像UTF-16那样使用复杂的算法。与UTF-16类似,UTF-32也包括UTF-32、UTF-32BE、UTF-32LE三种编码,UTF-32也同样需要BOM字符。仅用'ABC'举例:
UTF-32BE 00 00 00 41 00 00 00 42 00 00 00 43
UTF-32LE 41 00 00 00 42 00 00 00 43 00 00 00
UTF-32(Big Endian) 00 00 FE FF 00 00 00 41 00 00 00 42 00 00 00 43
UTF-32(Little Endian) FF FE 00 00 41 00 00 00 42 00 00 00 43 00 00 00
UTF-32(不带BOM) 00 00 00 41 00 00 00 42 00 00 00 43
13. UTF-8
UTF-16和UTF-32的一个缺点就是它们固定使用两个或四个字节,这样在表示纯ASCII文件时会有很多00字节,造成浪费。而RFC3629定义的UTF-8则解决了这个问题。
UTF-8用1~4个字节来表示代码点。表示方式如下:
UCS-2 (UCS-4) 位序列 第一字节 第二字节 第三字节 第四字节
U+0000 .. U+007F 00000000-0xxxxxxx 0xxxxxxx
U+0080 .. U+07FF 00000xxx-xxyyyyyy 110xxxxx 10yyyyyy
U+0800 .. U+FFFF xxxxyyyy-yyzzzzzz 1110xxxx 10yyyyyy 10zzzzzz
U+10000..U+1FFFFF 00000000-000wwwxx-
xxxxyyyy-yyzzzzzzz 11110www 10xxxxxx 10yyyyyy 10zzzzzz
可见,ASCII字符(U+0000~U+007F)部分完全使用一个字节,避免了存储空间的浪费。而且UTF-8不再需要BOM字节。
另外,从上表中可以看出,单字节编码的第一字节为[00-7F],双字节编码的第一字节为[C2-DF],三字节编码的第一字节为[E0-EF]。这样只要看到第一个字节的范围就可以知道编码的字节数。这样也可以大大简化算法。

14. java和Unicode的关系
下面这段话来自JDK文档关于Unicode的说明。
Programs are written using the Unicode character set. Information about this character set and its associated character encodings may be found at:
http://www.unicode.org
java程序是基于Unicode 字符集来编写的。关于这个字符集以及它的相关的编码可以在这个网站找到:
http://www.unicode.org
The Java platform tracks the Unicode specification as it evolves. The precise version of Unicode used by a given release is specified in the documentation of the class Character.
Java平台跟着Unicode的规范而变化。Java的每一个版本用到的准确的Unicode的版本号,定义在Character类的文档中。
Versions of the Java programming language prior to 1.1 used Unicode version 1.1.5. Upgrades to newer versions of the Unicode Standard occurred in JDK 1.1 (to Unicode 2.0), JDK 1.1.7 (to Unicode 2.1), J2SE 1.4 (to Unicode 3.0), and J2SE 5.0 (to Unicode 4.0).
Java 1.1用的是Unicode 1.1.5。JDK 1.1 用的是Unicode 2.0, JDK 1.1.7 用的是Unicode 2.1, J2SE 1.4用的是Unicode 3.0, and J2SE 5.0 用的是Unicode 4.0。
(J2SE 6.0 用的也是Unicode 4.0)
The Unicode standard was originally designed as a fixed-width 16-bit character encoding. It has since been changed to allow for characters whose representation requires more than 16 bits. The range of legal code points is now U+0000 to U+10FFFF, using the hexadecimal U+n notation. Characters whose code points are greater than U+FFFF are called supplementary characters. To represent the complete range of characters using only 16-bit units, the Unicode standard defines an encoding called UTF-16. In this encoding, supplementary characters are represented as pairs of 16-bit code units, the first from the high-surrogates range, (U+D800 to U+DBFF), the second from the low-surrogates range (U+DC00 to U+DFFF). For characters in the range U+0000 to U+FFFF, the values of code points and UTF-16 code units are the same.
Unicode标准最初的设计是16位固定宽度的字符编码. 后来变为允许用多于16位来表示字符。现在的合法的代码点从U+0000 to U+10FFFF, 16进制的表示方式。代码点大于U+FFFF 的字符叫做补充字符. 为了只用16位来表示全部范围的字符, Unicode标准定义了一套编码,叫做UTF-16. 在这个编码中,补充字符被表示为2个16-bit编码, 第一部分编码的范围是(U+D800 to U+DBFF), 第二部分编码的范围是 (U+DC00 to U+DFFF). 对于在 U+0000 to U+FFFF范围的字符来说, 代码点的值和UTF-16编码是一致的。

Java编程语言用16位的编码代表文本。使用UTF-16编码. 少数的APIs, 主要在Character 类中,用32-bit 的整数来代表代码点的单个实例。Java平台提供方法在两种表示方法之间进行转换。
This book uses the terms code point and UTF-16 code unit where the representation is relevant, and the generic term character where the representation is irrelevant to the discussion.
J2SE 技术规范现在使用术语代码点和 UTF-16 代码单元(表示法是相关的)以及通用术语字符(表示法与该讨论没有关系)。(API 通常使用名称 codePoint 描述表示代码点的类型 int 的变量,而 UTF-16 代码单元的类型当然为 char。)

Except for comments (§3.7), identifiers, and the contents of character and string literals (§3.10.4, §3.10.5), all input elements (§3.5) in a program are formed only from ASCII characters (or Unicode escapes (§3.3) which result in ASCII characters). ASCII (ANSI X3.4) is the American Standard Code for Information Interchange. The first 128 characters of the Unicode character encoding are the ASCII characters.
除了注释,标识符,字符常量,字符串常量,程序里其他的所有的输入元素只能是ASCII字符(或者通过转义得到的ASCII字符)。ASCII (ANSI X3.4) 是美国信息互换标准代码. Unicode字符编码中的前128个字符就是ASCII字符。

下面这段话来自API的关于java.lang.Character类的描述。
The set of characters from U+0000 to U+FFFF is sometimes referred to as the Basic Multilingual Plane (BMP). Characters whose code points are greater than U+FFFF are called supplementary characters. The Java 2 platform uses the UTF-16 representation in char arrays and in the String and StringBuffer classes. In this representation, supplementary characters are represented as a pair of char values, the first from the high-surrogates range, (\uD800-\uDBFF), the second from the low-surrogates range (\uDC00-\uDFFF).
范围是U+0000 到 U+FFFF 的字符,指的是Basic Multilingual Plane (BMP).
代码点比 U+FFFF 还大的字符叫增补字符. Java 2 平台在char arrays 和String 和 StringBuffer 类中使用UTF-16编码。在这种编码中,增补字符表示成两个char的值。第一个char的属于高代理范围(\uD800-\uDBFF), 第二个char属于低代理范围 (\uDC00-\uDFFF).



参考:
JDK文档关于Unicode的说明:
http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.1

15. char的含义
一个 char 表示一个 UTF-16 代码单元
将所有形式的 char 序列均解释为 UTF-16 序列
16. 什么是gb2312
GB2312是汉字字符集和编码的代号,中文全称为“信息交换用汉字编码字符集”,由中华人民共和国国家标准总局发布,1981年5月1日实施。GB是“国标” 二字的汉语拼音缩写。GB2312字符集只收录简化字汉字,以及一般常用字母和符号,主要通行于中国大陆地区和新加坡等地。
GB2312 共收录有7445个字符,其中简化汉字6763个,字母和符号682个。

标准的介绍:
http://www.nits.gov.cn/sc2/jishufile1.asp
http://zh.wikipedia.org/w/index.php?title=GB_2312&variant=zh-cn
所有字符的列表:
http://www.mytju.com/classcode/tools/QuWeiMa_FullList.asp
GB2312字符集与编码对照表(和荣版)
http://cuimingda.com/2008/12/gb2312.html
和荣笔记 - GB2312 字符集与编码对照表
http://www.herongyang.com/gb2312_gb/about.html


17. 什么是区位码
GB2312将所收录的字符分为94个区,编号为01区至94区;每个区收录94 个字符,编号为01位至94位。GB2312的每一个字符都由与其唯一对应的区号和位号所确定。例如:汉字“啊”,编号为16区01位。

GB2312字符集的区位分布表:

  区号    字数    字符类别
   01      94    一般符号
   02      72    顺序号码
   03      94    拉丁字母
   04      83    日文片假名
   05      86    日文片假名
   06      48    希腊字母
   07      66    俄文字母
   08      63    汉语拼音符号
   09      76    图形符号
10-15            备用区
16-55    3755    一级汉字,以拼音为序
56-87    3008    二级汉字,以笔划为序
88-94            备用区
18. 什么是GB2312编码
 GB2312 原始编码 (encoding) 是对所收录的每个字符都用两个字节 (byte) 表示。第一字节为“高字节”,由字符的区号值加上 32 而形成;第二字节为“低字节”,由字符的位号值加上 32 而形成。例如:汉字“啊”,编号为 16 区 01 位。它的高字节为 16 + 32 = 48 (0x30),低字节为 01 + 32 = 33 (0x21),合并而成的编码为 0x3021。在区位号值上加 32 的原因大慨是为了避开低值字节区间。
 由于 GB2312 原始编码与 ASCII 编码的字节有重叠,现在通行的 GB2312 编码是在原始编码的两个字节上各加 128 修改而形成。例如:汉字“啊”,编号为 16 区 01 位。它的原始编码为 0x3021,通行编码为 0xB0A1。如果不另加说明,GB2312 常指这种修改过的编码。
19. 什么是gbk
 Unicode 1.1 GB 13000.1-93GBK
 GBK全名为汉字内码扩展规范,英文名Chinese Internal Code Specification。K 即是“扩展”所对应的汉语拼音(KuoZhan11)中“扩”字的声母。GBK 来自中国国家标准代码GB 13000.1-93。
 1993年,Unicode 1.1版本推出,收录了中国大陆、台湾、日本及韩国通用字符集的汉字,总共有20,902个。
 中国大陆订定了等同于Unicode 1.1版本的“GB 13000.1-93”“信息技术 通用多八位编码字符集(UCS) 第一部分:体系结构与基本多文种平面”。
 由于GB 2312-80只收录了6763个汉字,有不少汉字,如部分在GB 2312-80推出以后才简化的汉字(如“啰”),部分人名用字(如中国前总理朱镕基的“镕”字),台湾及香港使用的繁体字,日语及朝鲜语汉字等,并未有收录在内。中文电脑开发商,于是利用了GB 2312-80未有使用的编码空间,收录了所有出现在Unicode 1.1及GB 13000.1-93之中的汉字,制定了GBK编码。
 根据西方资料,GBK最初是由微软对GB2312的扩展,也就是CP936字码表 (Code Page 936)的扩展(原来的CP936和GB 2312-80一模一样),最初出现于Windows 95简体中文版中,由于Windows产品的流行和在大陆广泛被使用,中华人民共和国国家有关部门将其作为技术规范。注意GBK并非国家正式标准,只是国家技术监督局标准化司、电子工业部科技与质量监督司发布的“技术规范指导性文件”。虽然 GBK收录了所有Unicode 1.1及GB 13000.1-93之中的汉字,但是编码方式与Unicode 1.1及GB 13000.1-93不同。仅仅是GB 2312到GB 13000.1-93之间的过渡方案。

参考:
从这里可以看到gbk编码表
http://www.microsoft.com/globaldev/reference/dbcs/936.mspx


其他:
http://www.nits.gov.cn/sc2/jishufile1-2.asp
http://zh.wikipedia.org/w/index.php?title=GBK&variant=zh-cn

20. 什么是gb18030
 •  GB 18030,全称:国家标准GB 18030-2005《信息技术 中文编码字符集》,是中华人民共和国现时最新的内码字集,是GB 18030-2000《信息技术 信息交换用汉字编码字符集 基本集的扩充》的修订版。与GB 2312-1980完全兼容,与GBK基本兼容,支持GB 13000及Unicode的全部统一汉字,共收录汉字70244个。
 •  GB 18030主要有以下特点:
    * 采用多字节编码,每个字可以由1个、2个或4个字节组成。
    * 编码空间庞大,最多可定义161万个字符。
    * 支持中国国内少数民族的文字,不需要动用造字区。
 字节结构
 单字节,其值从0到0x7F。129 个码位
 双字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x40到0xFE(不包括0x7F)。23940 个码位
 四字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x30到0x39,第三个字节从0x81到0xFE,第四个字节从0x30到0x39。1587600 个码位

参考:
介绍
http://zh.wikipedia.org/w/index.php?title=GB_18030&variant=zh-cn

GB18030-2000 标准的详细内容:
http://www.foundertype.com.cn/product_oem_2.htm
GB18030优点
http://www.nits.gov.cn/sc2/jishufile1-3.asp
关于GB18030汉字编码标准集
http://tech.sina.com.cn/s/2001-07-26/1850.html
21. 如何查看GB 18030-2000的4字节组成的字符?
gb18030_4byte.jsp
22. 什么是ansi
 为使计算机支持更多语言,通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。比如:汉字 '中' 在中文操作系统中,使用 [0xD6,0xD0] 这两个字节存储。
 不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码。
 不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。
23. 什么是代码页
代码页 code page 是IBM 的传统术语,就是“一张字符编码表”,

参考:
http://www.microsoft.com/globaldev/reference/dbcs/936.mspx
24. gb2312和gbk和gb18030的关系
<html>
<head><title>Frame</title></head>
<frameset cols="30%, *, *, *,*">
<frame name="middle" src="gb2312.jsp">
<frame name="middle" src="gbk.jsp">
<frame name="middle" src="gb18030.jsp">
<frame name="left" src="htmlcode.jsp">
<frame name="left" src="unicode.jsp">
</frameset>
</html>

25. 从gb2312转换成unicode
import java.io.*;
import java.nio.*;
import java.nio.charset.*;
class GB2312Unicde {
   static OutputStream out = null;
   static char hexDigit[] = {'0', '1', '2', '3', '4', '5', '6', '7',
                             '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
   static int b_out[] = {201,267,279,293,484,587,625,657,734,782,827,
      874,901,980,5590};
   static int e_out[] = {216,268,280,294,494,594,632,694,748,794,836,
      894,903,994,5594};
   public static void main(String[] args) {
      try {
         out = new FileOutputStream("gb2312.gb");
         writeCode();
         out.close();
      } catch (IOException e) {
         System.out.println(e.toString());
      }
   }
   public static void writeCode() throws IOException {
      boolean reserved = false;
      String name = null;
      // GB2312 is not supported by JDK. So I am using GBK.
      CharsetDecoder gbdc = Charset.forName("GBK").newDecoder();
      CharsetEncoder uxec = Charset.forName("UTF-16BE").newEncoder();
      CharsetEncoder u8ec = Charset.forName("UTF-8").newEncoder();
      ByteBuffer gbbb = null;
      ByteBuffer uxbb = null;
      ByteBuffer u8bb = null;
      CharBuffer cb = null;
      int count = 0;
      for (int i=1; i<=94; i++) {
         // Defining row settings
         if (i>=1 && i<=9) {
            reserved = false;
            name = "Graphic symbols";
         } else if (i>=10 && i<=15) {
            reserved = true;
            name = "Reserved";
         } else if (i>=16 && i<=55) {
            reserved = false;
            name = "Level 1 characters";
         } else if (i>=56 && i<=87) {
            reserved = false;
            name = "Level 2 characters";
         } else if (i>=88 && i<=94) {
            reserved = true;
            name = "Reserved";
         }
         // writing row title
         writeln();
         writeString("");
         writeNumber(i);
         writeString(" Row: "+name);
         writeln();
         writeString("
");
         writeln();
         if (!reserved) {
            writeln();
            writeHeader();
           // looping through all characters in one row
            for (int j=1; j<=94; j++) {
               byte hi = (byte)(0xA0 + i);
               byte lo = (byte)(0xA0 + j);
               if (validGB(i,j)) {
                  // getting GB, UTF-16BE, UTF-8 codes
                  gbbb = ByteBuffer.wrap(new byte[]{hi,lo});
                  try {
                     cb = gbdc.decode(gbbb);
                     uxbb = uxec.encode(cb);
                     cb.rewind();
                     u8bb = u8ec.encode(cb);
                  } catch (CharacterCodingException e) {
                     cb = null;
                     uxbb = null;
                     u8bb = null;
                  }
               } else {
                  cb = null;
                  uxbb = null;
                  u8bb = null;
               }
               writeNumber(i);
               writeNumber(j);
               writeString(" ");
               if (cb!=null) {
                  writeByte(hi);
                  writeByte(lo);
                  writeString(" ");
                  writeHex(hi);
                  writeHex(lo);
                  count++;
               } else {
                  writeGBSpace();
                  writeString(" null");
               }
               writeString(" ");
               writeByteBuffer(uxbb,2);
               writeString(" ");
               writeByteBuffer(u8bb,3);
               if (j%2 == 0) {
                  writeln();
               } else {
                  writeString("   ");
               }
            }
            writeFooter();
         }
      }
      System.out.println("Number of GB characters worte: "+count);
   }
   public static void writeln() throws IOException {
      out.write(0x0D);
      out.write(0x0A);
   }
   public static void writeByte(byte b) throws IOException {
      out.write(b & 0xFF);
   }
   public static void writeByteBuffer(ByteBuffer b, int l)
      throws IOException {
      int i = 0;
      if (b==null) {
      writeString("null");
      i = 2;
      } else {
for (i=0; i<b.limit(); i++) writeHex(b.get(i));
      }
      for (int j=i; j<l; j++) writeString("  ");
   }
   public static void writeGBSpace() throws IOException {
      out.write(0xA1);
      out.write(0xA1);
   }
   public static void writeString(String s) throws IOException {
      if (s!=null) {
         for (int i=0; i<s.length(); i++) {
            out.write((int) (s.charAt(i) & 0xFF));
         }
      }        
   }
   public static void writeNumber(int i) throws IOException {
      String s = "00" + String.valueOf(i);
      writeString(s.substring(s.length()-2,s.length()));
   }
   public static void writeHex(byte b) throws IOException {
      out.write((int) hexDigit[(b >> 4) & 0x0F]);
      out.write((int) hexDigit[b & 0x0F]);
   }
   public static void writeHeader() throws IOException {
      writeString("<pre>");
      writeln();
      writeString("Q.W. ");
      writeGBSpace();
      writeString(" GB   Uni. UTF-8 ");
      writeString("   ");
      writeString("Q.W. ");
      writeGBSpace();
      writeString(" GB   Uni. UTF-8 ");
      writeln();
      writeln();
   }
   public static void writeFooter() throws IOException {
      writeString("</pre>");
      writeln();
   }
   public static boolean validGB(int i,int j) {
      for (int l=0; l<b_out.length; l++) {
         if (i*100+j>=b_out[l] && i*100+j<=e_out[l]) return false;
      }
      return true;
   }
}


26. 怎样给一个字符串编码
public byte[] getBytes(String charsetName)
                throws UnsupportedEncodingException
Encodes this String into a sequence of bytes using the named charset, storing the result into a new byte array.

27. 怎样得到一个字符串的unicode
public static String getUnicodeFromStr(String s){
String retS = "";
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
retS +=String.format("%1$04x",(int)c)+" ";
}
return retS;
}
public static String getUnicodeFromStr2(String s) throws UnsupportedEncodingException{
String retS = "";
byte [] bytes = s.getBytes("unicode");
for (int i = 0; i < bytes.length; i++) {
retS+=String.format("%1$02x",(int)(bytes[i]))+" ";
}
return retS;
}

28. Java支持多少种编码
import java.nio.charset.*;
import java.util.*;
public class Encode1 {
public static void main(String args[]) {
Map<String, Charset> availcs = Charset.availableCharsets();
Set<String> keys = availcs.keySet();
for (Iterator<String> iter =keys.iterator(); iter.hasNext();) {
System.out.println(iter.next());
}
}
}

29. Java的默认编码是什么?
import java.io.*;
public class Encode2 {
public static void main(String args[]) throws IOException {
FileWriter filewriter = new FileWriter("out");
String encname = filewriter.getEncoding();
filewriter.close();
System.out.println("default charset is: " + encname);
}
}

30. 联通
讲到这里,我们再顺便说说一个很著名的奇怪现象:当你在 windows 的记事本里新建一个文件,输入"联通"两个字之后,保存,关闭,然后再次打开,你会发现这两个字已经消失了,代之的是几个乱码!呵呵,有人说这就是联通之所以拼不过移动的原因。
其实这是因为GB2312编码与UTF8编码产生了编码冲撞的原因。
当一个软件打开一个文本时,它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。软件一般采用三种方式来决定文本的字符集和编码:
检测文件头标识,提示用户选择,根据一定的规则猜测
最标准的途径是检测文本最开头的几个字节,开头字节 Charset/encoding,如下表:
EF BB BF UTF-8
FE FF UTF-16/UCS-2, little endian
FF FE UTF-16/UCS-2, big endian
FF FE 00 00 UTF-32/UCS-4, little endian.
00 00 FE FF UTF-32/UCS-4, big-endian.

当你新建一个文本文件时,记事本的编码默认是ANSI(代表系统默认编码,在中文系统中一般是GB系列编码), 如果你在ANSI的编码输入汉字,那么他实际就是GB系列的编码方式,在这种编码下,"联通"的内码是:
c1 1100 0001
aa 1010 1010
cd 1100 1101
a8 1010 1000
注意到了吗?第一二个字节、第三四个字节的起始部分的都是"110"和"10",正好与UTF8规则里的两字节模板是一致的,
于是当我们再次打开记事本时,记事本就误 认为这是一个UTF8编码的文件,让我们把第一个字节的110和第二个字节的10去掉,我们就得到了"00001 101010",再把各位对齐,补上前导的0,就得到了"0000 0000 0110 1010",不好意思,这是UNICODE的006A,也就是小写的字母"j",而之后的两字节用UTF8解码之后是0368,这个字符什么也不是。这就 是只有"联通"两个字的文件没有办法在记事本里正常显示的原因。
而如果你在"联通"之后多输入几个字,其他的字的编码不见得又恰好是110和10开始的字节,这样再次打开时,记事本就不会坚持这是一个utf8编码的文件,而会用ANSI的方式解读之,这时乱码又不出现了。





你可能感兴趣的:(java,编程,jsp,J2SE)