網站公告 :


Delphi K.Top討論區 » 會員作品發表區(限本人創作發表) » 文字轉碼程式
發表新文章
 
主題:文字轉碼程式
瀏覽次數:11646
dllee
站務副站長




發表:315
回覆:2470
積分:1695
註冊:2002-04-15

發送簡訊給我
#1 發表時間:2004-10-09 07:58:07 IP:211.76.xxx.xxx 未訂閱

寫這個工具主要是整理兩天來在網路上搜尋的結果,
最後還是在 KTOP 找到解答
感謝 SANJYSAN 在 http://delphi.ktop.com.tw/topic.php?TOPIC_ID=55094
所發表的「萬用轉碼函數」總算是讓我以前在 DOS 下使用倚天碼的文件
可以重回 BIG5 碼的懷抱


由 黃國書 Kii Ali 的「技術_NT nls 問題」列表:
"20000"="c_20000.nls"    ;Taiwan 國家標準碼 CNS
"20001"="c_20001.nls"    ;Taiwan 公會碼    TCA
"20002"="c_20002.nls"    ;Taiwan 倚天碼    Eten
"20003"="c_20003.nls"    ;Taiwan        IBM5550
"20004"="c_20004.nls"    ;Taiwan 電信碼    Teletext
"20005"="c_20005.nls"    ;Taiwan 王安碼    Wang
應該包含大部分非BIG5的繁體中文,以我的 XP HomeEd. 預設只有裝 c_20000.nls
如果需要其他的 codepage 可以從 Windows 原版光碟中找,或是網路搜尋下載。

不想下載的就參考以下的原始碼吧

//---------------------------------------------------------------------------
// ◎ MS 定義支援的 codepage 及在 HTML 內的 CHARSET 代號對照表
//    
//    http://msdn.microsoft.com/workshop/author/dhtml/reference/charsets/charset4.asp
// ◎ 俄羅斯 Konstantin Kazarnovsky 對於 CP_nnnn.nls 與 C_nnnn.cls 檔的內容解析
//    http://webcenter.ru/~kazarn/eng/nls.htm
// ◎ 國人 黃國書 Kii Ali 所整理的「技術_NT nls 問題」
//    http://ftp.isu.edu.tw/pub/CPatch/faq/tech/tech_nlsnt.txt
// ◎ MS 說明如何自己加入 codepage
//    http://msdn.microsoft.com/library/en-us/vcce/htm/evc_appendices_1.asp
//    http://support.microsoft.com/default.aspx?scid=kb;EN-US;151701
// ◎ SANJYSAN 在 KTOP 所提供的「萬用轉碼函數」
//    http://delphi.ktop.com.tw/topic.php?TOPIC_ID=55094
// <2004-10-09> 整理 by Lee, Dong-Liang
//        http://dllee.ktop.com.tw
//---------------------------------------------------------------------------

#include
#pragma hdrstop

#include "CodePageUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TStringList *CodePageListSupported;
TStringList *CodePageList;
CPINFOEX CodePageInfoEx;
BOOL CALLBACK EnumCodePagesProc(LPTSTR lpCodePageString) // code page identifier string
{
    UINT CodePage=String(lpCodePageString).ToIntDef(0);
    if(IsValidCodePage(CodePage)) // code page
    {
    GetCPInfoEx(CodePage,0,&CodePageInfoEx);
    CodePageList->AddObject(CodePageInfoEx.CodePageName,(TObject*)CodePage);
    CodePageListSupported->AddObject(CodePageInfoEx.CodePageName,(TObject*)CodePage);
    }
    else
    {
    CodePageList->AddObject(String(lpCodePageString)+" **Not Installed**",
        (TObject*)CodePage);
    }
    return true;
}
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    CodePageList=new TStringList;
    CodePageListSupported=new TStringList;
    EnumSystemCodePages((CODEPAGE_ENUMPROC)EnumCodePagesProc, // callback function
    CP_SUPPORTED); // CP_INSTALLED: installed, CP_SUPPORTED: supported code pages
    Memo1->Lines->Add("This System Support All the following CodePage.");
    Memo1->Lines->Add("If the name of the CodePage is **Not Installed** means it is not installed.");
    Memo1->Lines->AddStrings(CodePageList);
    ComboBox1->Items->AddStrings(CodePageListSupported);
    ComboBox2->Items->AddStrings(CodePageListSupported);
    ComboBox1->ItemIndex=ComboBox1->Items->IndexOfObject((TObject*)950);
    ComboBox2->ItemIndex=ComboBox1->Items->IndexOfObject((TObject*)950);
    if(ComboBox1->ItemIndex<0)ComboBox1->ItemIndex=0;
    if(ComboBox2->ItemIndex<0)ComboBox2->ItemIndex=0;
    delete CodePageList;
    delete CodePageListSupported;
}
//---------------------------------------------------------------------------
// SANJYSAN http://delphi.ktop.com.tw/topic.php?TOPIC_ID=55094
// 萬用轉碼函數
#define UNICODE 0
void* __fastcall TForm1::CodeConvert(void *str, int code_from, int code_to, int MAXLENG)
{
    PWSTR wszUnicode    = NULL; //Unicode
    PSTR InStr        = NULL; //from Code
    PSTR OutStr        = NULL; //to Code
    int iLen        = 0;    //char length

    if (code_from!=UNICODE) // other to unicode
    {
    InStr = (char*)str;
    iLen = MultiByteToWideChar(code_from, 0, InStr, -1, NULL,0);
    wszUnicode = new wchar_t[MAXLENG+1];
    MultiByteToWideChar(code_from, 0, InStr, -1, wszUnicode,iLen);
    if (code_to==UNICODE) return wszUnicode;
    }
    else wszUnicode = (PWSTR)str;

    //unicode to other
    iLen = WideCharToMultiByte(code_to, 0, wszUnicode, -1, NULL,0,NULL, NULL);
    OutStr = new char[MAXLENG+1];
    WideCharToMultiByte(code_to, 0, wszUnicode, -1, OutStr,iLen,NULL, NULL);

    if (code_from!=UNICODE) delete [] wszUnicode;

    return OutStr;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    char *Output=NULL;
    char *Input=Memo1->Text.c_str();
    Output=(char*)CodeConvert(Input,
    (int)ComboBox1->Items->Objects[ComboBox1->ItemIndex],
    (int)ComboBox2->Items->Objects[ComboBox2->ItemIndex],
    Memo1->Text.Length()*2);
    Memo1->Text=AnsiString(Output);
    delete Output;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    if(OpenDialog1->Execute())
    Memo1->Lines->LoadFromFile(OpenDialog1->FileName);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
    if(SaveDialog1->Execute())
    {
    Memo1->Lines->SaveToFile(SaveDialog1->FileName);
    ShowMessage("File Saved");
    }
}
//---------------------------------------------------------------------------


對了,忘了說明,我把 SANJYSAN 小改了一下,主要是字串長度,
原本的方式我轉出來都只有一行,後來火大,直接設一個比較大的數值
就 OK 了,而且發現設超大結果也是正常,所以,我才會直接以 2 倍
大小來處理。 另外,就是本來想用它應該也可以作簡繁轉換,沒想到
效果實在是不好... 不過,在繁轉繁的部分,應該算是不錯了。


吃軟也吃硬 dllee.ktop.com.tw StatPlus 系統資源監測器 @ SoftKing VMASK - ViewMove Automation Software Kernel

發表人 - dllee 於 2004/10/09 08:07:53
------
http://blog.yam.com/dllee/

附加檔案:57431_CodePage.zip

conundrum
尊榮會員




發表:893
回覆:1272
積分:628
註冊:2004-01-06

發送簡訊給我
#2 發表時間:2004-10-09 13:38:47 IP:61.221.xxx.xxx 未訂閱



日語馬ㄟ通喔 哈哈 哈哈哈 一句話 真好

win2000上 執行 ok ok

試用過很多翻譯日文軟體 老是翻不準不然就是無法原貌呈現
除了 南極星老軟體也可以 原貌呈現日文 但在切換方式 令人髮指

殺咪 一點不通 議神 用於老東西的本文翻譯 只能說差了

這東西好EZ 哈哈 哈哈哈 使人抓狂




dllee
站務副站長




發表:315
回覆:2470
積分:1695
註冊:2002-04-15

發送簡訊給我
#3 發表時間:2004-10-09 23:32:46 IP:211.76.xxx.xxx 未訂閱

感謝 conundrum 的測試,讓我發現,一定要先去安裝
conundrum 大大所介紹的 Unicode 補完計畫:

參照頁:http://leoboard.cpatch.org/cgi-bin/topic.cgi?forum=21&topic=405&show=0
網址:http://search.cpatch.org/download/patchutil/unicodeaton/unicodeaton_240.exe

裝完之後,使用此工具,就可以轉簡轉繁,不過轉出來的是 BIG5 中的簡體造字(這也是之前我自己測出來效果很差,但裝了 Unicode 補完計畫後效果就還可接受),而不是真的對應的繁體字,算是小缺陷。同樣,在裝了 Unicode 補完計畫後,就可以用 BIG5 中的日文造字來顯示日文,所以,也可以把日文轉用 BIG5 來顯示,但前題是要安裝 Unicode 補完計畫,或至少要裝中國海字集 for windows 才能顯示日文造字。


吃軟也吃硬 dllee.ktop.com.tw StatPlus 系統資源監測器 @ SoftKing VMASK - ViewMove Automation Software Kernel

------
http://blog.yam.com/dllee/

SANJYSAN
一般會員




發表:5
回覆:10
積分:3
註冊:2002-05-28

發送簡訊給我
#4 發表時間:2004-10-11 14:10:47 IP:202.145.xxx.xxx 未訂閱

引言:

對了,忘了說明,我把 SANJYSAN 小改了一下,主要是字串長度,
原本的方式我轉出來都只有一行,後來火大,直接設一個比較大的數值
就 OK 了,而且發現設超大結果也是正常,所以,我才會直接以 2 倍
大小來處理。


因為原來的程式只是拿來轉一個字串而已,其長度來自:

iLen = MultiByteToWideChar(code_from, 0, InStr, -1, NULL,0);

所以遇上0x00的字串結尾自然就停了。要轉整篇的話,MAXLENG是個方法,但最好還是把整個buffer(file)的大小傳進去比較好。

引言:

另外,就是本來想用它應該也可以作簡繁轉換,沒想到
效果實在是不好... 不過,在繁轉繁的部分,應該算是不錯了。



簡繁體和codepage沒有關係,那是字形的關係。big5碼裡也有big5碼的簡體字形,gb碼裡也有gb碼的繁體字形,所以要簡繁轉換的話得另外轉字形才行。當然一般是內碼字形一起轉就是了。

要轉簡繁字形的話,你得在前面內碼轉碼完畢後,再呼叫一個API:

int LCMapString(
    LCID Locale,    // locale identifier
    DWORD dwMapFlags, // mapping transformation type
    LPCTSTR lpSrcStr, // source string
    int cchSrc,        // number of characters in source string
    LPTSTR lpDestStr, // destination buffer
    int cchDest        // size of destination buffer
);

MSDN上有對於這個API的說明,裡面有參數:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/nls_5s2v.asp

當然這些參數得另外設定,基本上沒辦法用內碼直接判斷,因gb與big5都同時具有簡繁字形的關係。除非你強迫指定成轉big5就自動變繁體,gb就自動變簡體,但不建議這麼做。

又LCMapString的字型轉換還有個有趣的功能。看看MSDN上的參數說明:

LCMAP_FULLWIDTH
LCMAP_HALFWIDTH
LCMAP_HIRAGANA
LCMAP_KATAKANA
LCMAP_LINGUISTIC_CASINGLCMAP_UPPERCASE
LCMAP_LOWERCASE
LCMAP_SIMPLIFIED_CHINESE
LCMAP_SORTKEY
LCMAP_TRADITIONAL_CHINESE
LCMAP_UPPERCASE

這也就是說,字形轉換也可以轉日文,你可以把日文裡的平假片假,半形全形等自由轉換....





dllee
站務副站長




發表:315
回覆:2470
積分:1695
註冊:2002-04-15

發送簡訊給我
#5 發表時間:2004-10-11 23:17:24 IP:211.76.xxx.xxx 未訂閱

感謝 SANJYSAN 的指教,說真的,沒有您的「萬用轉碼函數」
http://delphi.ktop.com.tw/topic.php?TOPIC_ID=55094
也不可能有這篇...

而您提到的 LCMapString 除了
LCMAP_SIMPLIFIED_CHINESE Windows NT 4.0 and later: Maps traditional Chinese characters to simplified Chinese characters.
LCMAP_TRADITIONAL_CHINESE Windows NT 4.0 and later: Maps simplified Chinese characters to traditional Chinese characters.
有比較明顯是簡繁轉換,其他的我實在是看不懂是由什麼轉到什麼...
有空再試試看吧...


吃軟也吃硬 dllee.ktop.com.tw StatPlus 系統資源監測器 @ SoftKing VMASK - ViewMove Automation Software Kernel

------
http://blog.yam.com/dllee/

dllee
站務副站長




發表:315
回覆:2470
積分:1695
註冊:2002-04-15

發送簡訊給我
#6 發表時間:2004-10-14 11:28:17 IP:220.139.xxx.xxx 未訂閱

已經試出來 SANJYSAN 所介紹的 LCMapString()
用 LCMAP_SIMPLIFIED_CHINESE 繁轉簡
用 LCMAP_TRADITIONAL_CHINESE 簡轉繁
在原 CodeConvert()
return OutStr;
前加上
LCMapString() 及對應的參數即可。
當然,如果所選用的參數與 From To 的 CodePage 選用不同,那結果就還是亂碼一堆 如果正確選用,如:
From : 936
To : 950
再用 LCMapString() 及 LCMAP_TRADITIONAL_CHINESE 就可以完美的簡轉繁

From : 950
To : 936
再用 LCMapString() 及 LCMAP_SIMPLIFIED_CHINESE 就可以完美的繁轉簡

這樣轉出來就像一般的簡繁互換軟體是一樣的了,效果就像之前我一直在用的
sos_admin 大大的
■【發表】e?繁???器 Ver1.0
http://delphi.ktop.com.tw/topic.php?TOPIC_ID=55939
真的好用!!

我平常也會使用漢書XP 來作簡繁互換,現在,這個簡繁互換的功能,預計要加入 StatPlus2 中,請期待...

PS1. 預告一下: StatPlus2 目前正在設計使用者自定熱鍵介面,這樣對於不了如何操作 regedit 的使用者來說,就可以方便使用 StatPlus 了。
PS2. TOGET 的軟體登錄服務實在是太爛了!! StatPlus2 從 2004-09-03 登錄更新到目前都還沒更新上。40天了耶!! SoftKing 則是軟體登錄大約一週就刊出。 


吃軟也吃硬 dllee.ktop.com.tw StatPlus 系統資源監測器 @ SoftKing VMASK - ViewMove Automation Software Kernel

------
http://blog.yam.com/dllee/

SANJYSAN
一般會員




發表:5
回覆:10
積分:3
註冊:2002-05-28

發送簡訊給我
#7 發表時間:2004-10-14 17:28:17 IP:202.145.xxx.xxx 未訂閱

引言:

而您提到的 LCMapString 除了
LCMAP_SIMPLIFIED_CHINESE Windows NT 4.0 and later: Maps traditional Chinese characters to simplified Chinese characters.
LCMAP_TRADITIONAL_CHINESE Windows NT 4.0 and later: Maps simplified Chinese characters to traditional Chinese characters.
有比較明顯是簡繁轉換,其他的我實在是看不懂是由什麼轉到什麼...
有空再試試看吧...



說明(個人判斷,實際上沒試過):

LCMAP_FULLWIDTH (轉全形字)
LCMAP_HALFWIDTH (轉半形字)
上面兩個可能用在日文(有分全形半形)或BIG5/GB的英文碼,譬如AA這樣的全半形字轉換。

LCMAP_HIRAGANA    (轉成平假名,日文)
LCMAP_KATAKANA    (轉成片假名,日文)
LCMAP_LINGUISTIC_CASINGLCMAP_UPPERCASE (不明)
LCMAP_LOWERCASE (轉小寫,應該是英文)
LCMAP_SIMPLIFIED_CHINESE (轉簡體)
LCMAP_SORTKEY (不明)
LCMAP_TRADITIONAL_CHINESE (轉繁體)
LCMAP_UPPERCASE (轉大寫,應該是英文)

引言:

當然,如果所選用的參數與 From To 的 CodePage 選用不同,那結果就還是亂碼一堆 如果正確選用,如:
From : 936 To : 950
再用 LCMapString() 及 LCMAP_TRADITIONAL_CHINESE 就可以完美的簡轉繁
From : 950 To : 936
再用 LCMapString() 及 LCMAP_SIMPLIFIED_CHINESE 就可以完美的繁轉簡



補充:
unicode本身同時支援簡繁體,所以應該也可以用。
再者,gb碼用LCMAP_TRADITIONAL_CHINESE的話應該也可以轉成gb碼繁體。
big5的話就不太確定了。





muta
一般會員




發表:0
回覆:2
積分:0
註冊:2004-01-06

發送簡訊給我
#8 發表時間:2004-11-22 17:06:05 IP:220.130.xxx.xxx 未訂閱

感謝兩位先進,解決我一直想要簡單轉換簡體到繁體的困擾
不敢單獨發一篇文章佔篇幅,綜合兩位的程式及發文,小弟寫成BCB可方便使用的函數如下:

// GB to BIG5
AnsiString __fastcall GBToBig5(const AnsiString str)
{
        PWSTR wszUnicode = NULL; //Unicode
    PSTR InStr = NULL; //from Code
    PSTR OutStr = NULL; //to Code
    int iLen = 0; //char length

    InStr = (char*)str.c_str();
    int InSize = str.Length();
    iLen = MultiByteToWideChar(936,0,InStr,InSize,NULL,0);
    wszUnicode = new wchar_t[iLen+1];
    MultiByteToWideChar(936,0,InStr,InSize,wszUnicode,iLen);

        // 簡轉繁
    PWSTR wszUnicode2 = new wchar_t[iLen+1];
        LCMapStringW(0x0404, // Locale id of taiwan
        LCMAP_TRADITIONAL_CHINESE,
        wszUnicode, iLen,
        wszUnicode2,iLen);

    //unicode to other
    int uiLen = WideCharToMultiByte(950,0,wszUnicode2,iLen,NULL,0,NULL,NULL);
    OutStr = new char[uiLen+1];
    WideCharToMultiByte(950,0,wszUnicode2,iLen,OutStr,uiLen,NULL,NULL);

        AnsiString ret = AnsiString(OutStr);
    delete [] OutStr ;
    delete [] wszUnicode;
    delete [] wszUnicode2 ;

    return ret ;
}




dllee
站務副站長




發表:315
回覆:2470
積分:1695
註冊:2002-04-15

發送簡訊給我
#9 發表時間:2004-11-22 21:06:06 IP:211.76.xxx.xxx 未訂閱

感謝 muta 的分享
原來我的處理順序錯了
我原本是把 LCMapString() 用在最後, 而您是用在中間... 改天再來試試有什麼不同。

再次感謝您的指教。


吃軟也吃硬 dllee.ktop.com.tw StatPlus 系統資源監測器 @ KTOP VMASK - ViewMove Automation Software Kernel

------
http://blog.yam.com/dllee/

z858328y
一般會員




發表:7
回覆:9
積分:3
註冊:2006-08-29

發送簡訊給我
#10 發表時間:2008-01-25 13:50:43 IP:59.115.xxx.xxx 訂閱

真是太感謝大大了,解決了很久的多國語言的問題


系統時間:2010-09-03 19:08:21,  線上使用者 259 / Max 3,401,主題數:92,416,回覆數:208,133。  聯絡我們 | Delphi.ktop討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!

趴趴狗旅遊網大花蓮旅遊網大花蓮民宿網花蓮市旅遊網花蓮市民宿網大南投旅遊網大南投民宿網
日月潭風景區日月潭旅遊網日月潭民宿網台東旅遊網台東民宿網集集旅遊網集集民宿網
關子嶺旅遊網關子嶺民宿網白河旅遊網白河民宿網
. . . . . . . .