2007年3月8日木曜日

ICUを使おう

ICUとは

IBM提供の文字コード変換ライブラリです。

主に、XercesでEUC-JPを正しく使うためににも使えます。

インストール for VC 8(VisualStudio 2005)

IBMのICUのページからICU4Cのicu-x.x.zipをダウンロードします(2006/02/26現在3.4が最新)。

icu-x.x.zipを適当なフォルダに解凍します。解凍して作られたフォルダicuを以後[ICU_FOLDER]と呼びます。

ラ イブラリのビルドは、[ICU_FOLDER]/source/allinone/allinone.slnファイルをVisualStudioで開きま す。このとき、allinone.slnがvc 7.1で作られているため変換しますか?と聞かれるので変換しましょう。

その後、アクティブなターゲットがDebugになっているのを確認して、ソリューションのビルドを行います。次に、アクティブなターゲットをReleaseに変更してソリューションのビルドを行います。

Debug 版→Release版の順でビルドを行うのは、出力されるexeが当たり前ですが、Debug版とRelease版で同名なので、exeについては Release版を残したいためです。ライブラリについては、Debug版はxxxd.dllとdが付いているため区別され、別ファイルとして保存されま す。

ビルドされたライブラリは、[ICU_FOLDER]/libへ出力されます。また、dll、exeは[ICU_FOLDER]/binに出力されます。

使い方

ICUを使うには、

  • [ICU_FOLDER]/includeディレクトリをincludeパスに追加
  • [ICU_FOLDER]/libの中の必要なライブラリをプロジェクトに追加
  • [ICU_FOLDER]/binのdllをPATHの通ったフォルダへコピーなどしてdllをロード出来る状態にする。

sjisをUNICODEへ変換

shift_jisをUNICODEへ変換するには、こんな感じです。windows向けという事で、shift_jisではなく、windows-31jを指定しています。

#include 
#include
#include

// ライブラリをリンクするためのおまじない
#ifdef _DEBUG
#pragma comment(lib, "icuucd.lib")
#else
#pragma comment(lib, "icuuc.lib")
#endif

int main(int /* argc */, char** /* argv */)
{
const char* const INPUT_STRING="hogeほげ/~";


UErrorCode error = U_ZERO_ERROR;

// 変換器の初期化
UConverter* cnv = ucnv_open("windows-31j", &error);
if(U_FAILURE(error))
{
// ICUのメモリ解放
u_cleanup();
return 1;
}

// 必要なメモリ量を確認
const int32_t unicodeLen
= ucnv_toUChars(cnv, 0, 0
, INPUT_STRING
, strlen(INPUT_STRING)
, &error);

if(0 == unicodeLen)
{
// 変換器解放
ucnv_close(cnv);
// ICUのメモリ解放
u_cleanup();
return 1;
}

error = U_ZERO_ERROR;
UChar* pBuf = new UChar[unicodeLen+1];
ucnv_toUChars(cnv, &pBuf[0], unicodeLen
, INPUT_STRING
, strlen(INPUT_STRING)
, &error);

if(U_FAILURE(error))
{
delete [] pBuf;
// 変換器解放
ucnv_close(cnv);
// ICUのメモリ解放
u_cleanup();
return 1;
}
pBuf[unicodeLen] = L'\0';

// 変換したUNICODE文字で何か処理をする

// 後始末
delete [] pBuf;
// 変換器解放
ucnv_close(cnv);
// ICUのメモリ解放
u_cleanup();
return 0;
}

UNICODEをsjisへ変換

UNICODEをsjis変換するには、こんな感じです。windows向けという事で、shift_jisではなく、windows-31jを指定しています。

#include 
#include
#include

// ライブラリをリンクするためのおまじない
#ifdef _DEBUG
#pragma comment(lib, "icuucd.lib")
#else
#pragma comment(lib, "icuuc.lib")
#endif

int main(int argc, char** argv)
{
const wchar_t* const INPUT_STRING=L"hogeほげ/~";

UErrorCode error = U_ZERO_ERROR;

// 変換器の初期化
UConverter* cnv = ucnv_open("windows-31j", &error);
if(U_FAILURE(error))
{
// ICUのメモリ解放
u_cleanup();
return 1;
}

// 必要なメモリ量を確認
const int32_t mbsLen
= ucnv_fromUChars(cnv, 0, 0
, INPUT_STRING
, wcslen(INPUT_STRING)
, &error);

if(0 == mbsLen)
{
// 変換器解放
ucnv_close(cnv);
// ICUのメモリ解放
u_cleanup();
return 1;
}

error = U_ZERO_ERROR;
char* pBuf = new char[mbsLen+1];
ucnv_fromUChars(cnv, &pBuf[0], mbsLen
, INPUT_STRING
, wcslen(INPUT_STRING)
, &error);
if(U_FAILURE(error))
{
delete [] pBuf;
// 変換器解放
ucnv_close(cnv);
// ICUのメモリ解放
u_cleanup();
return 1;
}
pBuf[mbsLen] = '\0';


// 変換した文字で何か処理をする

// 後始末
delete [] pBuf;
// 変換器解放
ucnv_close(cnv);
// ICUのメモリ解放
u_cleanup();
return 0;
}

マルチバイト・マルチバイト変換(C++らしい解答)

ICUを使って、マルチバイト文字をマルチバイト変換関数を実相してみます。

util.lzhを 見て下さい。そのうち、時間を作って説明を書きます。ひとまず、概要だけ。配列のデータ確保後のメモリ解放忘れを避けるため、boostの scoped_arrayを使っています。また、ucnv_openで確保したデータの解放し忘れを避けるため、UConvCloserというデストラク タでucnv_closeを呼び出すクラスを実相してます。

0 件のコメント: