gb3212java判断_GBK,GB3212 Unicode编码问题详解

计算机的数据是由1和0组成,这种数据在这里称作基本数据或物理数据

人们所理解的文字和符号在这里称作逻辑数据

* 编码是物理数据和逻辑数据的映射关系

* 编码是读写物理数据的契约

* 编码是计算机的"词汇量",不同编码表达范围不同,如:ASCII和GBK,这是由于排列组合的结果

* 编码间可以互相转换(通过Unicode),但可能会造成丢失逻辑信息

例子:

这里有两个不同的编码规则

编码规则A

物理数据

逻辑数据

1000

1001

1002

1003

编码规则B

物理数据

逻辑数据

1000

1001

1002

1003

对于逻辑数据"你好",不同编码有不同的物理数据:

- 编码A的你好:10001001

- 编码B的你好:10021003

对于物理数据"10001001",应用不同的编码,得到的结果不同:

- 编码A:你好

- 编码B:他坏

对于逻辑数据"我们",有的编码不能表达:

- 编码A的我们:10021003

- 编码B的我们:

GB2312

双字节,定长

包括一二级汉字和9区符号

高位低位一样,都是从0xA1~0xFE

汉字编码范围是0xB0A1~0xF7FE

GBK

双字节,定长

兼容GB2312

编码范围:0x8140~0xFEFE

所有字符都可以映射到Unicode2.0

GB18030-2000(GBK2K)

收藏少数民族字型

不定长,包含二字节部分和四字节部分

二字节部分兼容GBK

四字节部分是扩充字符,第一第三字节范围:0x81~0xFE,第二第四字节范围:0x30~0x39

Unicode

包括所有字符字型

各地区语言都可与之建立映射

异种语言的转换是通过Unicode来完成的

汉字从4E00开始

UTF(Unicode Text Format,Unicode文本格式)

1. 如果Unicode的16位的头9位是0,则用一个字节表示。

这个字节首位位0,省下7位保留原样

例子:

源字符:\u0034(0000 0000 0011 0100)

转化为: 34   (          0011 0100)

2. 如果Unicode的16位的头5位是0,则用两个字节表示。

首字节"110"开头,后面5位与源字符出去头5个0后的最高5位相同

二字节"10"开头,后面6位与源字符低6位相同

例子:

源字符:\u025d (0000 0010 0101 1101)

转化为:c99d (1100 1001 1001 1101)

3. 如果不符合上述规则,则用三个字节表示

首字节"1110"开头,后四位为源字符的高四位

二字节"10"开头,后六位为源字符中间六位

三自己"10"开头,后六位为源字符低六位

例子:

源字符:\u9da7 (1001 1101 1010 0111)

转化为:e9b6a7 (1110 1001 1011 0110 1010 0111)

Java中Unicode与UTF的关系

内存

介质

Unicode

writeUTF

----------->

readUTF

UTF

IPO模型

input(CharsetA) -> process(Unicode) -> Output(CharsetB)

SourceFile(.jsp,.java> -> .class -> output

- jsp->temp file->class->browser,os,console,db

- app,servlet->class->browser,os,console,db

JSP到.class文件的过程

JSP源文件中有中文字符-"中文",它的的GB2312编码"D6 D0 CE C4"

Jsp-Charset

JSP文件中

Java文件中

Class文件中

GB2312

D6 D0 CE C4(GB2312)

从\u4E2D\u6587(Unicode)

到E4 B8 AD E6 96 87(UTF)

E4 B8 AD E6 96 87(UTF)

ISO8859-1

D6 D0 CE C4(GB2312)

从\u00D6 \u00D0 \u00CE \u00C4

到C3 96 C3 90 C3 8E C3 84(UTF)

C3 96 C3 90 C3 8E C3 84(UTF)

无(默认=file.encoding)

假设:ISO8859-1

同ISO8859-1

同ISO8859-1

同ISO8859-1

详解第一行:

1. 编写JSP源文件,存为GB2312格式[D6 D0 CE C4, D6D0=中 CEC4=文]

2. jspc把JSP源文件转化为临时java文件,并把字符串按照GB2312映射到Unicode,

并用UTF格式写入Java文件 [E4 B8 AD E6 96 87]

3. 把临时文件编译成class文件 [E4 B8 AD E6 96 87]

4. 运行时,先从class文件中用readUTF读出字符串,在内存中是Unicode

[4E 2D 65 87(在Unicode中,4E2D=中, 6587=文)]

5. 根据jsp-charset=GB2312把Unicode转化成字节流[D6 D0 CE C4]

6. 把字节流输出到IE中,并设置IE编码为GB2312(隐藏在HTTP头里)[D6 D0 CE C4]

7. 用IE"简体中文"查看结果 ["中文"正确显示]

详解第二行:

1. 编写JSP源文件,存为GB2312格式[D6 D0 CE C4, D6D0=中 CEC4=文]

2. jspc把JSP源文件转化为临时java文件,并把字符串按照ISO8859-1映射到Unicode,

并用UTF格式写入Java文件 [C3 96 C3 90 C3 8E C3 84]

3. 把临时文件编译成class文件 [C3 96 C3 90 C3 8E C3 84]

4. 运行时,先从class文件中用readUTF读出字符串,在内存中是Unicode

[00 D6 00 D0 00 CE 00 C4 (啥都不是!!)]

5. 根据jsp-charset=ISO8859-1把Unicode转化成字节流[D6 D0 CE C4]

6. 把字节流输出到IE中,并设置IE编码为ISO8859-1(隐藏在HTTP头里)[D6 D0 CE C4]

7. 用IE"西欧字符"查看结果 [乱码,其实是4个ASCII字符,但由于大于128,所以看起来象乱码]

8. 用IE"简体中文"查看结果 ["中文"正确显示]

Servlet源文件到.class文件的过程

javac -encoding

Compile-charset

Servlet源文件中

Class文件中

等效Unicode码

GB2312

D6 D0 CE C4(GB2312)

E4 B8 AD E6 96 87(UTF)

\u4E2D\u6587

(在Unicode中="中文")

ISO8859-1

D6 D0 CE C4(GB2312)

E4 B8 AD E6 96 87(UTF)

\u00D6 \u00D0 \u00CE \u00C4

(在每个字节前加了"00")

无(默认)

D6 D0 CE C4(GB2312)

同ISO8859-1

同ISO8859-1

详解第一行:

1. 编写Servlet源文件,存为GB2312格式[D6 D0 CE C4, D6D0=中 CEC4=文]

2. javac -encoding GB2312 把java文件编译成.class文件[E4 B8 AD E6 96 87(UTF)]

3. 运行时,先从class文件中用readUTF读出字符串,在内存中是Unicode[4E 2D 65 87]4. 根据servlet-charset=GB2312把Unicode转化成字节流[D6 D0 CE C4(GB2312)]

5. 把字节流输出到IE中,并设置IE编码为GB2312(隐藏在HTTP头里)[D6 D0 CE C4(GB2312)]

6. 用IE"简体中文"查看结果 ["中文"正确显示]

详解第二行:

1. 编写Servlet源文件,存为GB2312格式[D6 D0 CE C4, D6D0=中 CEC4=文]

2. javac -encoding GB2312 把java文件编译成.class文件[C3 96 C3 90 C3 8E C3 84(UTF)]

4. 运行时,先从class文件中用readUTF读出字符串,在内存中是Unicode

[00 D6 00 D0 00 CE 00 C4]

5. 根据jsp-charset=ISO8859-1把Unicode转化成字节流[D6 D0 CE C4(GB2312)]

6. 用IE"西欧字符"查看结果 [乱码]

7. 用IE"简体中文"查看结果 ["中文"正确显示]

class的输出字符串

内存中是Unicode,但这个Unicode表示什么,要看是从哪种字符集映射过来的

Unicode"\u00D6 \u00D0 \u00CE \u00C4"表示了什么?

1. 直接用Unicode码表来对照,得到4个特殊字符

2. 如果与ISO8859-1映射,则去掉前面的"00",得到 D6 D0 CE C4

3. 如果与GB2312映射,则可能没有对应上(若对不上,将得到0x3f,也就是问号),即便对应上也是特殊符号

所以同样的Unicode字符,可以解释成不同的样子

Class在输出字符串前,会将Unicode的字符串按照某中内码重新生成字节流,

相当于string.getByte(xCharset)

* 如果是Servlet,由httpResponse.setContentType(xxx)来指定

* 如果是JSP,由 来指定

* 如果是Java,由file.encoding来指定,默认为ISO8859-1

输出到DB

假设DB是ISO8859-1编码

序号

步骤说明

结果

1

在IE中输入“中文”

D6 D0 CE C4

IE

2

IE把字符串转变成UTF,并送入传输流中

E4 B8 AD E6 96 87

3

Servlet接收到输入流,用readUTF读取

4E 2D 65 87(unicode)

Servlet

4

编程者在Servlet中必须把字符串根据GB2312还原为字节流

D6 D0 CE C4

5

编程者根据数据库内码ISO8859-1生成新的字符串

00 D6 00 D0 00 CE 00 C4

6

把新生成的字符串提交给JDBC

00 D6 00 D0 00 CE 00 C4

7

JDBC检测到数据库内码为ISO8859-1

00 D6 00 D0 00 CE 00 C4

JDBC

8

JDBC把接收到的字符串按照ISO8859-1生成字节流

D6 D0 CE C4

9

JDBC把字节流写入数据库中

D6 D0 CE C4

10

完成数据存储工作

D6 D0 CE C4 数据库

以下是从数据库中取出数的过程

11

JDBC从数据库中取出字节流

D6 D0 CE C4

JDBC

12

JDBC按照数据库的字符集ISO8859-1生成字符串,并提交给Servlet

00 D6 00 D0 00 CE 00 C4 (Unicode)

13

Servlet获得字符串

00 D6 00 D0 00 CE 00 C4 (Unicode)

Servlet

14

编程者必须根据数据库的内码ISO8859-1还原成原始字节流

D6 D0 CE C4

15

编程者必须根据客户端字符集GB2312生成新的字符串

4E 2D 65 87

(Unicode)

Servlet准备把字符串输出到客户端

16

Servlet根据<Servlet-charset>生成字节流

D6D0 CE C4

Servlet

17

Servlet把字节流输出到IE中,如果已指定<Servlet-charset>,还会设置IE的编码为<Servlet-charset>

D6 D0 CE C4

18

IE根据指定的编码或默认编码查看结果

“中文”(正确显示)

IE

步骤:4,5,15,16要编码者自己完成

4,5   一句话: new String(source.getBytes("GB2312"), "ISO8859-1")

15,16 一句话: new String(source.getBytes("ISO8859-1"), "GB2312")

Q:为什么会有"?"号

A:转换分两种情况

1. ACode->Unicode->BCode

2. Unicode->BCode

可以看到异种语言的转换是通过Unicode来完成的

对于(1),当ACode的内容BCode无法映射时,则得到Unicode代码"\ufffd"

对于(2),如果BCode不能映射,则得到"0x3f",也就是问号

"李":GBK为"C0EE"->Unicode为"674E"->ISO8859-1 *失败,因为ISO8859-1没有与674E对应的字符

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值