シフトJISとUTF-8の相互変換関数
日本語を含む文字列をPOCOの関数やクラスに渡す場合は、シフトJISコードのままではなく、あらかじめUTF-8コードに変換しておく必要があります。シフトJISのままにしておくと、前述のような文字化けが発生することがあります。そこで、シフトJISからUTF-8に変換する処理が必要になってくるのですが、ヨーロッパ生まれのPOCOはシフトJISには対応していません。当然、シフトJISとUTF-8を相互変換する関数も用意されていませんので、POCOの関数を利用したシフトJISとUTF-8の相互変換関数を作ってみました(Windows環境のみ)。
Win32 APIだけでも変換はできるのですが、POCOにはUTF-8コードとUTF-16コードの相互変換用の関数が用意されているので、その関数とWin32 APIを利用しています。シフトJISとUTF-8との変換は、直接変換するのではなく、いったんUTF-16にしてから変換しています。
シフトJISをUTF-8に変換
まず、シフトJIS→UTF-16→UTF-8の変換です。シフトJIS→UTF-16の変換では、APIをそのまま使っています。
std::wstring ShitJIStoUTF16( const std::string& str ) { int len = ::MultiByteToWideChar( CP_ACP, 0, str.c_str(), -1, NULL, 0 ); // (1) if ( len>0 ) { std::vector<wchar_t> utf16( len ); // (2) if ( ::MultiByteToWideChar( CP_ACP, 0, str.c_str(), -1, &utf16[0], len ) ) // (3) return std::wstring( &utf16[0] ); } return NULL; }
(1)の行で、APIのMultiByteToWideCharを用いて、str
をUTF-16コードに変換するのに必要なバッファのサイズ(ワイド文字数)を求めています。CP_ACPは、日本語WindowsではシフトJISコードを指定していることになります。(2)でワイド文字であるwchar_t型の領域を確保して、(3)で実際に変換しています。
MultiByteToWideCharの定義は次のようになっています。
int MultiByteToWideChar( UINT CodePage, // コードページ DWORD dwFlags, // 文字の種類を指定するフラグ LPCSTR lpMultiByteStr, // マップ元文字列のアドレス int cchMultiByte, // マップ元文字列のバイト数 LPWSTR lpWideCharStr, // マップ先ワイド文字列を入れる // バッファのアドレス int cchWideChar // バッファのサイズ );
バッファのサイズを0にして呼び出すと必要なバッファサイズを求めることができます。文字の種類を指定するフラグは特に指定する必要はありません。マップ元文字列のバイト数に-1を指定した場合は、文字列はNULLで終わっていると見なして自動的に長さが計算されます。
UTF-16→UTF-8の変換にはPOCOのtoUTF8
関数を使います。まとめると、シフトJIS→UTF-8の変換ソースは次のようになります。
#include "poco/UnicodeConverter.h" std::string ShitJIStoUTF8( const std::string& str ) { std::string utf8; // UTF-16にして、UTF-8に変換 Poco::UnicodeConverter::toUTF8( ShitJIStoUTF16( str ), utf8 ); return utf8; }
UTF-8をシフトJISに変換
次に、UTF-8→UTF-16→シフトJISの変換です。UTF-16→シフトJISの変換では、APIをそのまま使っています。
std::string UTF16toShitJIS( const std::wstring& wstr ) { int len = ::WideCharToMultiByte( CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL ); // (1) if ( len>0 ) { std::vector<char> sjis( len ); // (2) if ( ::WideCharToMultiByte( // (3) CP_ACP, 0, wstr.c_str(), -1, &sjis[0], len, NULL, NULL ) ) return std::string( &sjis[0] ); } return NULL; }
(1)の行で、APIのWideCharToMultiByteを用いてwstr
をシフトJISコードに変換するために必要なバッファのサイズを求めています。CP_ACPは、日本語WindowsではシフトJISコードを指定していることになります。(2)でchar_t型の領域を確保(終端のNULLも含まれている)して、(3)で実際に変換しています。
WideCharToMultiByteの定義は次のようになっています。
int WideCharToMultiByte( UINT CodePage, // コードページ DWORD dwFlags, // 処理速度とマッピング方法を // 決定するフラグ LPCWSTR lpWideCharStr, // ワイド文字列のアドレス int cchWideChar, // ワイド文字列の文字数 LPSTR lpMultiByteStr, // 新しい文字列を受け取る // バッファのアドレス int cchMultiByte, // 新しい文字列を受け取る // バッファのサイズ LPCSTR lpDefaultChar, // マップできない文字の // 既定値のアドレス LPBOOL lpUsedDefaultChar // 既定の文字を使ったときに // セットするフラグのアドレス );
バッファのサイズを0にして呼び出すと必要なサイズを求めることができます。ワイド文字列の文字数を-1にすると、文字列はNULLで終わっていると見なして自動的に長さが計算されます。その他は特に指定する必要はありません。
UTF-8→UTF-16の変換には、POCOのtoUTF16
関数を使います。まとめると、UTF-8→シフトJISの変換ソースは次のようになります。
#include "poco/UnicodeConverter.h" std::string UTF8toShitJIS( const std::string& str ) { std::wstring wstr; // UTF-8をUTF-16に変換 Poco::UnicodeConverter::toUTF16( str, wstr ); return UTF16toShitJIS( wstr ); // UTF-16をシフトJISに変換 }
Win32APIのみを使った場合に比べると、POCOの関数を使っている分だけコード量が少なくなっています。