在 Powerbuilder 下轉換 UTF-8 文字為 ANSI 文字
PB10 + 版本 & Pocket Powerbuilder 2.1+ 版本
直接使用 String 就可以轉換
lbl_src = blob( ls_string1 , encodingutf8! )
ls_string2 = string( lbl_src , encodingansi!)
powerbuilder 9 (含以下版本) 就得借助 Windows API 來完成轉換
首先,你必須宣告外部函數(declare external functions)
function ulong MultiByteToWideChar(
ulong CodePage,
ulong dwflags,
ref string lpmultibytestr,
ulong cchmultibyte,
ref blob lpwidecharstr,
ulong cchwidechar
) library "kernel32.dll"
function ulong WideCharToMultiByte(
ulong CodePage,
ulong dwFlags,
ref blob lpWideCharStr,
ulong cchWideChar,
ref string lpMultiByteStr,
ulong cbMultiByte,
ref string lpUsedDefaultChar,
ref boolean lpUsedDefaultChar
) library "kernel32.dll"
然後下面實做一個轉換函數
string of_utf8_to_ansi(string as_utf8)
程式碼:
//轉換 utf-8 -> ansi
//use a wide-char native string as pivot
constant ulong CP_ACP = 0
constant ulong CP_UTF8 = 65001 //UTF8的PAGE CODE
string ls_wide, ls_ansi, ls_null
blob lbl_wide
ulong ul_len
boolean lb_flag
setnull(ls_null)
lb_flag = false
//取得 utf-8 轉換 wide-char 後的字串長度
setnull(lbl_wide)
ul_len = multibytetowidechar(CP_UTF8, 0, as_utf8, -1, lbl_wide, 0)
//配置記憶體空間給字串
ls_wide = space(ul_len * 2)
lbl_wide = blob(ls_wide)
//轉換 utf-8 -> wide char
ul_len = multibytetowidechar(CP_UTF8, 0, as_utf8, -1, lbl_wide, ul_len)
//取得ANSI字串長度
setnull(ls_ansi)
ul_len = widechartomultibyte(CP_ACP, 0, lbl_wide, -1, ls_ansi, 0, ls_null, lb_flag)
//配置足夠空間給 windows 寫入
ls_ansi = space(ul_len)
//轉換 wide-char -> ansi
ul_len = widechartomultibyte(CP_ACP, 0, lbl_wide, -1, ls_ansi, ul_len, ls_null, lb_flag)
return ls_ansi
下面利用 inet.GetUrl 去取得 API 內容,這個內容是 UTF-8 編碼的,所以就用 of_utf_to_ansi 去變更編碼:
先建立一個 internetresult 物件,名為 n_internetresult
然後在 n_internetresult 上建立 of_utf8 to_ansi 函數(function),把上面代碼複製進去
再來建立 instance variables
String is_data
最後編輯 internetdata 內建函數(function)
內容:
Blob lblb_data
lblb_data = data
is_data = of_utf8_to_ansi(string(iblb_data))
Return 1
之後就可以在需要的地方呼叫使用
n_internetresult i_ir
inet i_net
String ls_empl , ls_url , ls_name
Integer li_ret
i_ir = Create n_internetresult
i_net = Create inet
ls_empl = "0099685153"
ls_url = "http://mysite.com/api/GetEmployeeName.cfm?no=" + ls_empl
li_ret = i_net.GetUrl(ls_url , i_ir)
if li_ret < 0 then
//網路錯誤
messagebox("result" , "Network Error !")
else
ls_name = i_ir.is_data
messagebox("result" , "Employee Name is " + ls_name)
end if
Destroy inet
Destroy i_ir
參考 https://stackoverflow.com/questions/22336948/powerbuilder-importfile-of-utf-8-converting-utf-8-to-ansi
留言
实测用这种方式转字符串非常慢,比系统提供的FromUnicode和ToUnicode还慢。建议改用adostream的方法,使用简单,效率还高。
比如从unicode转ansi
OLEObject ole_ADOStream
ole_ADOStream = CREATE OLEObject
li_rtn = ole_ADOStream.ConnectToNewObject("ADODB.Stream")
ole_ADOStream.Charset = "unicode"
ole_adostream.Type = 1 //二进制数据Binary
ole_ADOStream.Open()
ole_ADOStream.Write(lbl_unicode)
ole_ADOStream.Position = 0
ole_ADOStream.Type = 2 //文本数据
ls_ansi = ole_ADOStream.readtext()
ole_ADOStream.Close()
destroy ole_ADOStream
注意lbl_unicode头部要有说明是big endian还是litte endian的标记,big endian是FEFF,little enddian是FFFE。
感謝提供另一種編碼方式,我不會用系统提供的FromUnicode和ToUnicode主要是powerbuilder6不支援,另外它也無法轉utf-16以外的編碼,所以不實用。我主要是解析uft-8文件。
確實,Byte Length使用 -1 是讓API自動偵測長度,是有可能遇到問題的,那是因為基於我使用的環境所以才如此設計。
如果,使用您的方法轉 UTF-8,程式碼將如下:
OLEObject ole_ADOStream
ole_ADOStream = CREATE OLEObject
li_rtn = ole_ADOStream.ConnectToNewObject("ADODB.Stream")
ole_ADOStream.Charset = "utf-8" //來源編碼方式
ole_adostream.Type = 1 //二进制数据Binary
ole_ADOStream.Open()
ole_ADOStream.Write(lbl_unicode)
ole_ADOStream.Position = 0
ole_ADOStream.Type = 2 //文本数据
ls_ansi = ole_ADOStream.readtext()
ole_ADOStream.Close()
destroy ole_ADOStream