事情的起因是客户那边要存入某个西欧字符"Ð",提示脚本出错,
于是就一起看看字符集到底是怎么回事,在此之前甚少了解字符集的问题:
--SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
--SET NLS_LANG=AMERICAN_AMERICA.US7ASCII
--SET NLS_LANG=AMERICAN_AMERICA.AL32UTF8
SET NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1
sqlplus richel/richel@hksg0102
column test_char format a15
column client_nls_lang format a15
column client_os_set format a15
column db_server_set format a10
--insert into characters_test values('AL32UTF8','ZHS16GBK','ZHS16GBK','中文');
insert into characters_test values('AL32UTF8','ZHS16GBK','WE8ISO8859P1','中文');
select * from characters_test;
commit;
上述是测试dos环境下数据库字符集,客户os字符集,和客户端nls的不同设置时,同样的字符“中文”
在数据库中实际存储的内容(dump结果);
我的注册表的缺省值:AMERICAN_AMERICA.WE8MSWIN1252
假设数据库A和客户端B,客户端所在的操作系统C。
1,数据库A在创建的时候会选定一个字符集,该字符集在使用过程中是不可更改的。
假定为AL32UTF8.
2,客户端所在的操作系统C有个默认的字符集ZHS16GBK;
3,客户端的dos 环境的NLS_LANG的值设为AMERICAN_AMERICA.WE8ISO8859P1;
我们执行:INSERT INTO TEST VALUES('中文');
“中文” --GBK 编码表示为: “ D6 D0 CE C4”(16进制);或者"214,208,206,196" (10进制)
就是告诉数据库,我向你传递的该二进制流是“WE8ISO8859P1” 字符集的编码表示形式。
你应该根据你自己的表示方法(AL32UTF8)作适当的转换。
(实际上他传递的是ZHS16GBK字符集的表示形式)
就对应转换为:"195,150,195,144,195,142,195,132" UTF-8 编码格式.
所以数据库中实际存放的就是"195,150,195,144,195,142,195,132"
Unicode是与ISO-8859-1兼容。
214:11 010110->11000011,10010110->195,150
208:11 010000->11000011,10010000->195,144
206:11 001110->11000011,10001110->195,142
196:11 000100->11000011,10000100->195,132
所以就转变为: 195,150,195,144,195,142,195,132。
unicode utf-8
中:4E2D 11100100,10111000,10101101(228,184,173)
文:6587 11100110,10010110,10000111(230,150,135)
11000011,10010110 (195,150)
”中文“ 在数据库AL32UTF8中的存储形式:
DB_SERVER_SET CLIENT_OS_SET CLIENT_NLS_LANG TEST_CHAR DUMP(T.TEST_CHAR,16)
AL32UTF8 ZHS16GBK AL32UTF8 ¿¿ Typ=1 Len=4: d6,d0,ce,c4
--(按照gbk编码原样存储)
AL32UTF8 ZHS16GBK ZHS16GBK ¿¿ Typ=1 Len=6:
228,184,173,230,150,135
--(按照gbk与unicode的转换规格转换)
--(unicode又转换为utf-8来传输,存储)
知识点:
WE8ISO8859P1--是8bits表示
US7ASCII --是7bits表示
UTF8 -- 表示规则复杂些.
UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:
UCS-2编码(16进制) UTF-8 字节流(二进制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx
例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx
10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 110001 001001, 用这个比特流依次代替模板中的x,得
到:11100110 10110001 10001001,即E6 B1 89。
见http://fmddlmyy.home4u.china.com/text6.html
Unicode只与ASCII兼容(更准确地说,是与ISO-8859-1兼容),
与GB码不兼容。例如“汉”字的Unicode编码是6C49,而GB码是BABA
Unicode也是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。
Unicode的学名是"Universal Multiple-Octet Coded Character Set",简称为UCS。UCS可以看作是
"Unicode Character Set"的缩写
UCS只是规定如何编码,并没有规定如何传输、保存这个编码。例如“汉”字的UCS编码是6C49,我可以用4
个ascii数字来传输、保存这个编码;也可以用utf-8编码:3个连续的字节E6 B1 89来表示它。关键在于通信
双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的方案。
UTF-8的一个特别的好处是它与ISO-8859-1
完全兼容
。Unicode是与ISO-8859-1兼容。
(但是ISO-8859-1并不与utf-8兼容,所以当ISO-8859-1编码存入
utf-8数据库时候,同样要按照unicode=>utf-8的规则转换。
就是:UTF-8就是以8位为单元对UCS进行编码)UTF是“UCS Transformation Format”的缩写。
更正对utf-8与iso8859-1关系的理解