轉換 BIG5、GB2312、UTF-8、Unicode 與 wchar_t
在硬碟裡發現這篇去年寫的舊文,放到 blog 上備查。
單純轉換
我們大致上會需要以下幾種 encoding 之間的相互轉換。
- BIG5
- GB2312
- UTF-8
- Unicode
- wchar_t
其中,Unicode 指 UCS2-LE、UCS2-BE、UCS4-LE 或 UCS4-BE 等 encoding,而 wchar_t 則視平台而定。純粹的 encoding 互轉的話,由於 Unicode 號稱能納萬物,所以建議的轉換程序如下:
- BIG5 <-> Unicode/UTF-8
- BIG5 -> Unicode/UTF-8 -> GB2312
- GB2312 <-> Unicode/UTF-8
- GB2312 -> Unicode/UTF-8 -> BIG5
而若以「外部檔案用與平台無關的 encoding 如 BIG5、GB2312 或 UTF-8,內部程式使用 wchar_t 執行演算法」的準則來看的話,我們會需要以下幾種 encoding 轉換:
- BIG5 <->
wchar_t - GB2313 <->
wchar_t - UTF-8 <->
wchar_t
進階轉換
另外,除了純粹的 encoding 轉換之外,也許有時還會需要更進一步的轉換機制:
- 處理非一對一對應:好比在繁簡體中文之間,有所謂一對多的困擾,一個簡體字,可能對應到多個繁體字。若有能夠依據前後文決定如何選取一對多的多個字中的哪一個字,這樣子的轉換會比單純的 encoding 轉換還要來得精準。
- 詞彙轉換:能轉換同義異形的兩岸詞彙用語。
轉換工具:libiconv
在 UNIX 上,首推 iconv,這是 libiconv 的 command-line wrapper,Linux 及 FreeBSD 的 kernel 也是用 libiconv 做 encoding 轉換的。依據 platform 的不同,libiconv 能夠支援的 encoding 也會有所不同,只要在該平台上的 libiconv 有支援的任兩個 encoding,libiconv 都能互相轉換。libiconv 亦有 Windows porting,可至 GnuWin32 網站抓。libiconv 轉換的機制是:
- 如果可以一對一轉換 (i.e. 有 table 支援),就做一對一轉換
- 否則,便先轉換成某一種 unicode,再轉成欲轉換的 encoding
因此,要使用 libiconv 在各個平台上,理論上我們只需要注意該平台的 libiconv 有支援哪些 encoding 即可。以下是我使用 libiconv 曾碰過的一些問題:
- 在 FreeBSD 4 的 libiconv 沒有
wchar_t支援,這是由於 FreeBSD 4 沒有正式支援wchar_t的緣故。在 FreeBSD 5 上就有正式支援wchar_t了。 - 在 Linux 上,RedHat 7、跟 RedHat 9,印象中都有
wchar_t支援,在 Linux 上使用 libiconv 對我們常會用到的 encoding 間做轉換,沒有問題。 - 在 Windows 上的 libiconv,亦沒有
wchar_t支援[1]。 - libiconv 不認得七個 BIG5 擴充字:碁, 銹, 裏(請改用'裡'), 墻, 恒, 粧, 嫺,無法將之轉換成對應的 UTF-8;但 Windows API 認得且可以轉換成 UTF-8。
轉換工具:ConvertZ
在 Windows 上,兩岸間最有名的轉碼工具便是 ConvertZ。ConvertZ 所列出的那些轉碼選項,只要在安裝 Windows 時有安裝好該 encoding 的 windows 組件,ConvertZ 便有辦法作轉換。另外,ConvertZ 亦有針對兩岸語言的不同,另外做一些一對多及詞彙轉換的工作。同時,ConvertZ 也有多種使用方法,方便各種應用情境。詳細使用說明請見 ConvertZ 網頁。
轉換工具:Windows API
大致上使用兩個 API:MultiByteToWideChar() 跟 WideCharToMultiByte()。這兩個 APIs 能在 wide-character 與 multi-byte character 之間作轉換,其中,CodePage 這個參數指的是 multi-byte character 的 encoding,常用的有兩種:
CP_ACP:ANSI code page,在 Windows API 裡,這指的是 Windows 安裝平台,好比繁體中文的CP_ACP預設是 BIG5。不過,在使用上,需搭配 C locale 一起用,也就是說,CP_ACP其實是跟著 setlocale() 所設定的 locale 走的。CP_UTF8:指定轉換的 multi-byte character 的 encoding 為 UTF-8。在 Windows 上,我們可以藉由指定CP_UTF8,在wchar_t與 utf-8 之間作轉換。
詳細參數、用法請見 MSDN。
2007-01-11 補充:Joel 的這篇《The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)》[2]寫的不錯,講 encoding/unicode 講的很清楚。
- 2008-01-03 新增:這是 libiconv 版本的問題,請見《Right libiconv version for Windows》。 ↩
- 中譯:《每個軟體開發者都絕對一定要會的Unicode及字元集必備知識(沒有藉口!)》。 ↩



7 Comments
後來發現,是 iconv 的 BIG5 這個 encoding 不認得那七個擴充字,改用 iconv 的 CP950 這個 encoding 即可。
一个将UTF-8码转换为GB2312的实例:#include "stdafx.h"#include <windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
WCHAR lsWideChar[10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
char lsChar[10] = {0xE6, 0xB5, 0x8B, 0xE8, 0xAF, 0x95, 0x30, 0x31, 0x32, 0x00};
// memcpy(lsWideChar, lsChar, sizeof lsChar);
char lsMultiByte[20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// char lsMultiByte[20] = {0xb2, 0xe2, 0xca, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; char *lpStr = "测试123";
DWORD lwWord;//先将UTF-8转换为WideChar
if (MultiByteToWideChar( CP_UTF8, 0, lsChar, 10,
lsWideChar, 10) == 0)
{
lwWord = GetLastError();
}//再将WideChar转换为MultiByte WideCharToMultiByte( CP_ACP, 0, lsWideChar, -1,
lsMultiByte, 256, NULL, NULL );
return 0;
}
這... shinemen 是不是寫錯了啊?
請教要如何用iconv()轉下列幾個字為UTF-8?(綉、琼、椀)
ps. 試了BIG5, CP950都不行
arphen,
請問您想要從 UTF-8 轉成 big5/cp950 還是從從 big5/cp950 轉成 UTF-8?這幾個字只有在 Unicode (UTF-8) 裡才有,big5/cp950 裡面沒有,所以無法轉換。
好文章,收藏一下
這裡有用 Perl 在 Windows 下呼叫 WideCharToMultiByte 及 MultiByteToWideChar 的實作,非 use Encode。
http://seanlin.o4u.com/2008/11/windows-perl-58xxx-unicode.html
4 Backlinks
為了解決這種情況,所以必須使用wide-character專用的function以及library,像是量測字串長度就必須改用wcslen()之類的function。 reference: big-endian, little-endian 轉換 BIG5、GB2312、UTF-8、Unicode 與 wchar_t 寬字符標量L"xx"在VC6.0/7.0和GNU g++中的不同實現
2006-6-27 为什么要用utf-8 # 轉換 BIG5、GB2312、UTF-8、Unicode 與 wchar_t # 百度搜索帮助中心-空间帮助 # Google和MSN域名遭劫 可能是万网竞争对手所为 # Blog搜索引擎简单比较 # debug # 字体的市场 # pt, px, DPI: 关于长度单位的误解
http://www.jeffhung.net/blog/articles/jeffhung/261/
[...] 我總說,FreeBSD 5 比 FreeBSD 4 好很多,因為 wide character/string support 在 FreeBSD 4 上,根本就是殘廢狀態。但到底差了多少呢?我一直也都說不上來。今天看到 ijliao’s blog 的這篇《FreeBSD 官方網頁改版》,跑去參訪了一下新版的 FreeBSD.org,結果逛到 FreeBSD C99 and POSIX® Conformance Project,從最後一個表「Wide Character/String Support」裡,終於知道 FreeBSD 4 的 wide character/string support,到底有多殘廢。看著整排的 N/A,心中不禁感嘆,還好我在一年前就毅然決然地 migrate 到 FreeBSD 5 了,要不然開著殘廢破車寫一大堆需要 i18n 的程式,肯定痛苦要死。 [...]
Post a Comment