這個'?'字的轉換為什麼是這個結果(GBK和GB18030互轉)

jacksonkingdom發表於2011-11-08

http://www.itpub.net/thread-1164171-1-1.html

select convert('?','ZHS16GBK','ZHS32GB18030') A,
convert('?','ZHS32GB18030','ZHS16GBK') B,
convert('?','ZHS32GB18030','ZHS32GB18030') C,
dump('?') D,
dump(convert('?','ZHS32GB18030','ZHS32GB18030')) E
from dual;
-----結果如下---------------------------------------
A B C D E
? ?? ? Typ=96 Len=2: 254,159 Typ=1 Len=2: 254,159

資料庫、客戶端和作業系統字符集都是GBK,應用時發現這個字'?'從GB18030轉碼到GBK有問題,在這裡進行實驗。從編碼看兩個字符集這個字都有相同的編碼FE 9F,也就是254,159。
為什麼相互轉換的時候會變成‘?’和‘??’,我試過編碼在'?'字附近的一些其它字,發現編碼為FE XX的這個區,很多字都有這個轉換成問號的問題,能幫忙解釋一下這個問題是怎麼產生的嗎。

這個問題基本弄清楚了,解釋如下:
首先說字符集,GBK字符集有80個字元是後來增補的,因為需要與GB18030相容,所以放在GB18030的PUA區(此時這80個字元也在Unicode中有自己的對應的一套編碼了,這一套編碼在GB18030和GBK中的對映是一致的),後來這80個字元被Unicode字符集收錄,於是在Unicode中有了自己的第二套編碼,但是這第二套編碼是不被GBK所相容,僅GB18030可識別,這些字元的新編碼也叫非PUA編碼。
簡單說,這幾個字元從GBK到Unicode,對應編碼為A,從GB18030到Unicode,對應編碼為A和A',Oracle在轉換時選擇的就是轉為A',A'是轉不回GBK編碼的。這就是第一個'?出現'的原因。
做一個實驗可驗證:
select convert('?','ZHS16GBK','ZHS32GB18030') A,
convert(convert('?','UTF8','ZHS32GB18030'),'ZHS16GBK','UTF8') A1,
dump(convert('?','UTF8','ZHS32GB18030')) A2
from dual;
A A1 A2
-- -- ------------------------
? ? Typ=1 Len=3: 228,182,174
'?'字的Unicode的非PUA編碼是4DAE,換算成UTF8的編碼方式是11100100 10110110 10101110,剛好是228,182,174

而且從轉換結果看,我們有理由相信Oracle在進行convert時是把源字符集的字元先轉換到Unicode字符集,然後再轉換到目標字符集。
再做另一個實驗:
select
dump(convert('?','ZHS32GB18030','ZHS16GBK')) B,
dump(convert(convert('?','UTF8','ZHS16GBK'),'ZHS32GB18030','UTF8') )B1,
dump(convert('?','UTF8','ZHS16GBK')) B3
from dual;
B B1 B3
-------------------------- -------------------------- ------------------------
Typ=1 Len=4: 131,54,207,57 Typ=1 Len=4: 131,54,207,57 Typ=1 Len=3: 238,161,163

確實B和B1兩種轉換結果相同。另外對原貼中的'??'的解釋,我們從B3的結果看,從GBK轉換到UTF8時,轉換後的UTF8編碼對應的Unicode編碼為E863,轉換結果是正確的。而從E863轉換到GB18030時結果是131,54,207,57,這個換算後對應的編碼是8336 CF39,對應不到任何GB18030的字元,所以顯示'??',但具體131,54,207,57是如何產生的,我還沒有確切弄明白,可能是Oracle的BUG,也可能是對PUA區選擇的問題。
以下是那80個字以及對應的GBK編碼(GB18030編碼也相同),PUA編碼和非PUA編碼(這兩個是Unicode編碼)
漢字 GBK編碼 PUA編碼 非PUA編碼
? FE50 E815 2E81
? FE51 E816 20087
? FE52 E817 20089
? FE53 E818 200CC
? FE54 E819 2E84
? FE55 E81A 3473
? FE56 E81B 3447
? FE57 E81C 2E88
? FE58 E81D 2E8B
? FE59 E81E 9FB4
? FE5A E81F 359E
? FE5B E820 361A

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23590362/viewspace-1056221/,如需轉載,請註明出處,否則將追究法律責任。

相關文章