在PowerBuilder下轉換簡繁體中文字
聲明:這是在Windows XP SP3繁體中文版環境底下的方式,不一定適用於英文版外掛繁體中文套件及Windows XP簡體版。
這是PB10的版本,如果你是PB10以下的版本,請注意external function宣告的方式不需要使用";ansi"。
首先宣告 instant 變數 :
然後是 external Function :
如果你要將簡體轉換為繁體:
定義一個Function : of_BIG52GBK(blob ablb_src) returns blob
如果你要將繁體轉換為簡體:
定義一個Function : of_GBK2BIG5(blob ablb_src) returns blob
說明:
在 Function 中全程都以Blob處理,原因在於PowerBuilder 的 String 變數本身如果你將取得的資料放入 String 變數後,它會嘗試去進行文字編碼,而這個編碼會因應OS本身設定的區域進行字碼對照轉換。在PB10以下的版本,假如從檔案讀取文件內容,則要以StreamMode來讀取成blob,如果以LineMode讀取為String,它會以 ANSI 原則去對照 繁體中文字碼表,因此如果找不到相關字碼則會將該字碼呈現 ? 號(0x3F),因此將失去原本取得的簡體字來源正確性。但是如果以PB10(含)以後的版本以LineMode或是TextMode讀取 String,則它會試圖轉換為 unicode ,但由於文件檔案內容本身是 ANSI 編碼,則會先轉為 UNICODE 對應碼,再試圖對照繁體中文字碼表,則結果可想而知,整個 String 內容將完全走樣。
所以處理其他編碼字串時,首先從來源(不管是Internet或是File)最好讀取時皆以 Blob 變數全成處理,直到編碼轉換完成為止。如此可以正確保留來源資料的正確性。
簡單示範一下從網路取得資料後的轉換,對象是大陸網站的HTML,通常的編碼都是GB2312:
這是PB10的版本,如果你是PB10以下的版本,請注意external function宣告的方式不需要使用";ansi"。
首先宣告 instant 變數 :
// 區域語系
Constant long LCMAP_TRADITIONAL_CHINESE=67108864
Constant long LCMAP_SIMPLIFIED_CHINESE=33554432
// 編碼方式
constant Uint CP_ANSI = 0 // default to ANSI code page
constant Uint CP_OEM = 1 // default to OEM code page
constant Uint CP_MAC = 2 // MAC code page
constant Uint CP_TANSI = 3 // THREAD ANSI code page
constant Uint CP_SYMB = 42 // SYMBOL
constant Uint CP_WIN874 = 874 // "windows-874" "泰文 (Windows)"
constant Uint CP_2022_JP_SJ = 932 // "iso-2022-jp" "日文 (Shift-JIS)"
constant Uint CP_GB2312 = 936 // 簡體中文 (GB2312)
constant Uint CP_KR = 949 // "euc-kr" "韓文"
constant Uint CP_BIG5 = 950 // 950 為 "big5" "繁體中文 (Big5)"
constant Uint CP_UNICODE_BE = 1201 // "unicodeFFFE" "Unicode (Big-Endian)"
constant Uint CP_WIN1258 = 1258 // "windows-1258" "越南文 (Windows)"
constant Uint CP_USERD = 50000 // "x-user-defined" "使用者定義"
constant Uint CP_AUTO = 50001 // "_autodetect_all" "自動選取"
constant Uint CP_2022_JP_J = 50220 // "iso-2022-jp" "日文 (JIS)"
constant Uint CP_2022_KR = 50225 // "iso-2022-kr" "韓文 (ISO)"
constant Uint CP_JP_AUTO = 50932 // "_autodetect" "日文 (自動選取)"
constant Uint CP_KR_AUTO = 50949 // "_autodetect_kr" "韓文 (自動選取)"
constant Uint CP_JP_EUC = 51932 // "euc-jp" "日文 (EUC)"
constant Uint CP_KR_EUC = 51949 // "euc-kr" "韓文 (EUC)"
constant Uint CP_GB2312_HZ = 52936 // "hz-gb-2312" "簡體中文 (HZ)"
constant Uint CP_UTF7 = 65000 // "utf-7" "Unicode (UTF-7)"
constant Uint CP_UTF8 = 65001 // Unicode (UTF-8)
然後是 external Function :
// 此處API是以符合PB10,及使用Blob傳遞資料方式改寫,略與MSDN上的有點出入
function ulong MultiByteToWideChar(UINT CodePage, ulong dwFlags , ref blob lpMultiByteStr , int cbMultiByte, ref blob lpWideCharStr , ulong cchWideChar) library "kernel32.dll" alias for "MultiByteToWideChar"
function ulong WideCharToMultiByte(UINT CodePage, ulong dwFlags, ref blob lpWideCharStr, ulong cchWideChar, ref blob lpMultiByteStr, ulong cbMultiByte, ref string lpUsedDefaultChar , ref boolean lpUsedDefaultChar) LIBRARY "kernel32.dll" alias for"WideCharToMultiByte;Ansi"
function ulong LCMapString(ulong Locale , ulong dwMapFlags , ref blob lpSrcStr , ulong cchSrc , ref blob lpDestStr , ulong cchDest) LIBRARY "kernel32.dll" ALIAS FOR "LCMapStringW"
如果你要將簡體轉換為繁體:
定義一個Function : of_BIG52GBK(blob ablb_src) returns blob
uLong lul_nlen , lul_swp
Blob lblb_wzs , lblb_map , lblb_dst
String ls_default = "?" , ls_null
Boolean lb_udc = False
setnull(ls_null)
if isnull(ablb_src) then Return blob(" ")
// 取得blob(ansi) 轉成 unicode 所需要的長度
lul_nlen = Len(ablb_src)
SetNull(lblb_wzs)
lul_swp = MultiByteToWideChar(CP_GB2312 , 0 , ablb_src , -1 , lblb_wzs , 0)
lblb_wzs = blob(space(lul_swp))
//轉換Gb碼到Unicode碼,使用了API函數MultiByteToWideChar
MultiByteToWideChar(CP_GB2312 , 0 , ablb_src , -1 , lblb_wzs , lul_nlen)
lul_nlen = Len(lblb_wzs)
lblb_map = blob(space(lul_nlen) , EncodingANSI!)
//轉換Gb碼簡體到Gb碼繁體,使用API函數LCMapString,台灣碼表1028,大陸碼表2052
LCMapString(1028 , LCMAP_TRADITIONAL_CHINESE , lblb_wzs , -1 , lblb_map , lul_nlen)
SetNull(lblb_dst)
lul_swp = WideCharToMultiByte(CP_BIG5 , 0 , lblb_map , -1 , lblb_dst , 0 , ls_null , lb_udc)
lblb_dst = blob(space(lul_swp) , EncodingANSI!)
//轉換Unicode碼到Big5碼,使用API函數WideCharToMultiByte
WideCharToMultiByte(CP_BIG5 , 0 , lblb_map , -1 , lblb_dst , lul_swp , ls_default , lb_udc)
Return lblb_dst
如果你要將繁體轉換為簡體:
定義一個Function : of_GBK2BIG5(blob ablb_src) returns blob
uLong lul_nlen
Blob lblb_wzs , lblb_map , lblb_dst
String ls_default = "?"
Boolean lb_udc = false
if isnull(ablb_src) then Return blob(" ")
// 取得blob(ansi) 轉成 unicode 所需要的長度
lul_nlen = Len(ablb_src)
lblb_wzs = blob(space(lul_nlen))
//轉換BIG5碼到Unicode碼,使用了API函數MultiByteToWideChar
MultiByteToWideChar(CP_BIG5 , 0 , ablb_src , -1 , lblb_wzs , lul_nlen)
lblb_map = blob(space(lul_nlen))
//轉換Gb碼簡體到Gb碼繁體,使用API函數LCMapString,台灣碼表1028,大陸碼表2052
LCMapString(1028 , LCMAP_SIMPLIFIED_CHINESE , lblb_wzs , -1 , lblb_map , lul_nlen)
lblb_dst = blob(space(lul_nlen) , EncodingANSI!)
//轉換Unicode碼到BGK碼,使用API函數WideCharToMultiByte
WideCharToMultiByte(CP_GB2312 , 0 , lblb_map , -1 , lblb_dst , lul_nlen , ls_default , lb_udc)
Return lblb_dst
說明:
在 Function 中全程都以Blob處理,原因在於PowerBuilder 的 String 變數本身如果你將取得的資料放入 String 變數後,它會嘗試去進行文字編碼,而這個編碼會因應OS本身設定的區域進行字碼對照轉換。在PB10以下的版本,假如從檔案讀取文件內容,則要以StreamMode來讀取成blob,如果以LineMode讀取為String,它會以 ANSI 原則去對照 繁體中文字碼表,因此如果找不到相關字碼則會將該字碼呈現 ? 號(0x3F),因此將失去原本取得的簡體字來源正確性。但是如果以PB10(含)以後的版本以LineMode或是TextMode讀取 String,則它會試圖轉換為 unicode ,但由於文件檔案內容本身是 ANSI 編碼,則會先轉為 UNICODE 對應碼,再試圖對照繁體中文字碼表,則結果可想而知,整個 String 內容將完全走樣。
所以處理其他編碼字串時,首先從來源(不管是Internet或是File)最好讀取時皆以 Blob 變數全成處理,直到編碼轉換完成為止。如此可以正確保留來源資料的正確性。
簡單示範一下從網路取得資料後的轉換,對象是大陸網站的HTML,通常的編碼都是GB2312:
inet linet_1
n_internetresult lir_data //這是繼承 PB 的 internetresult 物件
blob lblb_htm
String ls_url , ls_htm
linet_1 = Create inet
lir_date = Create n_internetresult
ls_url = "http://www.chinatelecom.com.cn/corp/index.html"
linet_1.GetURL(ls_url , lir_data)
lblb_htm = of_GBK2BIG5(lir_data.ib_data)
ls_htm = String(lblb_htm , EncodingANSI!)
destroy linet
destroy lir_data
留言
我依照您的code,在PB11.5進行實作,但一直試不出來.
我的OS是Window XP SP3,繁體版,
底下是大約的code:
ls_t = "業"
lb_b = blob(ls_t, EncodingANSI!)
lb_r = of_BIG52GBK(lb_b)
ls_r = string(lb_r, EncodingANSI!)
但卻無法正常回傳"業"的簡體,傳回了"珛 ",
請問, 我是否有未注意到的地方呢?
謝謝
這個問題出在這一行
ls_r = string(lb_r, EncodingANSI!)
知道為什麼函數轉換簡體字進出函數都必須使用blob變數承接嗎?
原因就在您使用string轉譯後存入ls_r1變數時就會進行字元編碼對照轉換了,所以你永遠看不到正確的「簡體字」。使用blob變數PB的VM不會對此種變數進行「字元編碼對照」,因此整個函數過程只要跟簡體字資料有關的都是存在BLOB變數處理的。
由於PB的VM這個「好心」的動作,所以您才可以於String變數操作ANSI編碼與UNICODE編碼的中文字,而不用考慮太多,但也因為這個「好心」的動作導致您在使用異種字碼表時產生不必要的轉換。
給您看一張用Convert-Z轉換的結果
https://lh5.googleusercontent.com/-53HTy6sC2qA/T73PVcLCYrI/AAAAAAAAAgA/WFUERAxEi7s/s600/convert-z-docc.png
小弟目前也是在測試繁體轉簡體部分,也是卡在blob部分,我想請問的是如果無法使用string(lb_r, EncodingANSI!)方式呈顯簡體文字,那要如何呈現簡體文字呢?
謝謝
PB10的VM使用作業系統的核心編碼方式,所以string會使用作業系統的字碼對照表(想知道作業系統對照表,可以查看[控制台][地區與語言選項][進階]),變更作業系統語言可以讓它正常顯示,但我想你不會這麼做,因為變更作業系統語言可能會導致某些軟體更新不正常(例如office update),如果只是要檢視,我的做法會將該簡體字資料放到一個本地html檔裡面,然後設定html編碼方式,利用PB內嵌Web Browser OLE 瀏覽該html檔案:
假如你的簡體字內容放在lb_r中,前後就加編碼方式lb_html = blob('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"></head><pre>') + lb_r + blob('</pre><body></body></html>')
然後儲存lb_html到html檔案,這個檔案用瀏覽器開啟就可以正常檢視內容,當然你也可以把瀏覽器OLE嵌入你的程式,讓它直接開啟就好了。
//宣告external functions
Function Long LCMapString(Long Locale,Long dwMapFlags,String lpSrcStr,Long cchSrc,ref String lpDestStr,Long cchDest) LIBRARY "kernel32.dll" Alias For "LCMapStringW;unicode"
//最重要的就是.....Alias For "LCMapStringW;unicode"
//然後
//簡轉繁
string ls_out,ls_in
long ll_in_len
ls_in = as_big5
ll_in_len = len(ls_in)*2+1
ls_out = space(ll_in_len)
LCMapString(2052,LCMAP_SIMPLIFIED_CHINESE, ls_in,-1, ls_out, ll_in_len)
Return ls_out
//繁轉簡
string ls_in,ls_out
long ll_in_len
ls_in = as_gbk
ll_in_len = len(ls_in)*2+1
ls_out = space(ll_in_len)
LCMapString(2052,LCMAP_TRADITIONAL_CHINESE,ls_in,-1,ls_out,ll_in_len)
Return ls_out
PB8有無提供big-5 轉utf8 的function ?
(目前GOOLE不到資料)
若無提供,我要如何將big-5轉成uft8??