LoginSignup
9
8

More than 5 years have passed since last update.

C/C++ におけるプラットフォームごとの文字変換処理

Posted at

ここではクロスプラットフォームに利用できる ICU と OS 固有の関数 (Windows/OSX) の3つの例を紹介する。クロスプラットフォームに利用できる候補として libiconv (iconv) もあるが今回取り上げない。出来れば ICU を使うべき。

ICU

ucnv_toUChars/ucnv_fromUChars を使う。

/* ucnv_toUChars の例。エラー処理を端折ってる点に注意 */
UConverter * converter = ucnv_open("shift_jis", &status);
const char *ms = "test";
size_t length = strlen(ms);
UErrorCode code = U_ZERO_ERROR;
size_t capacity = length * ucnv_getMinCharSize(converter) + 1;
UChar *us = (UChar *) calloc(capacity, sizeof(UChar));
int written = ucnv_toUChars(converter, us, capacity, ms, length, &code);
ucnv_close(converter);

/* ucnv_fromUChars の例。エラー処理を端折ってる点に注意 */
UConverter * converter = ucnv_open("shift_jis", &status);
const UChar us[] = { 't', 'e', 's', 't', 0 } ;
size_t length = u_strlen(us);
UErrorCode code = U_ZERO_ERROR;
size_t capacity = length * ucnv_getMaxCharSize(converter) + 1;
char *ms = (char *) calloc(capacity, sizeof(char));
int written = ucnv_fromUChars(converter, ms, capacity, us, length, &code);
ucnv_close(converter);

pre-flighting 形式も使用できるが、ここでは事前に必要なサイズを ucnv_get(Min|Max)CharSize で計算してから変換する処理にした。

Windows

Windows API の一部として入ってる MultiByteToWideChar/WideCharToMultiByte を使う。

/* MultiByteToWideChar の例。エラー処理を端折ってる点に注意 */
const char *ms = "test";
size_t length = strlen(ms);
UINT codepage = CP_UTF8;
/* pre-flighting 形式で事前に変換される長さを求める */
int capacity = MultiByteToWideChar(codepage, 0 /* MB_PRECOMPOSED */, ms, length, NULL, 0);
wchar_t *ws = (wchar_t *) calloc(capacity, sizeof(wchar_t));
/* マルチバイト文字からワイド文字に変換 */
int written = MultiByteToWideChar(codepage, 0, ms, length, ws, capacity);

/* WideCharToMultiByte の例。エラー処理を端折ってる点に注意 */
const wchar_t *ws= L"test";
size_t length = wcslen(ws);
UINT codepage = CP_UTF8;
/*
 * pre-flighting 形式で事前に変換される長さを求める
 * 後ろ2つの引数は変換失敗時の処理だがここではシステム規定とする
 */
int capacity = WideCharToMultiByte(codepage, 0 /* WC_SEPCHARS */, ws, length, NULL, 0, NULL, NULL);
char *ms = (char *) calloc(capacity + 1, sizeof(char));
/* ワイド文字からマルチバイト文字に変換 */
int written = WideCharToMultiByte(codepage, 0, ws, length, ms, capacity, NULL, NULL);

最初の引数は CP_ ではじまる定数以外 Code Page Identifiers から使用したい文字コードからコードページを指定する(例えば Shift_JIS の場合 932)。例外は UTF-16 で wchar_t が元々 UTF-16 形式で格納されているため。

OSX

CFString または NSString を使うが、ここでは CFString を使う。

/* CFStringRef に変換する。エラー処理を端折ってる点に注意 */
const char *ms = "test";
size_t length = strlen(ms);
CFStringEncoding encoding = kCFStringEncodingMacJapanese;
CFStringRef s = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *) ms, length, encoding, FALSE);

/* CFStringRef からバイト文字を取得する形で文字変換する。エラー処理を端折ってる点に注意 */
CFStringRef s = CFSTR("test");
CFIndex length = CFStringGetLength(us);
CFStringEncoding encoding = kCFStringEncodingMacJapanese;
size_t capacity = CFStringGetMaximumSizeForEncoding(length, encoding);
UInt8 *ms = (UInt8 *) calloc(capacity, sizeof(UInt8));
CFIndex written;
CFStringGetBytes(s, CFRangeMake(0, length), encoding, '?', FALSE, ms, capacity, &written);

ShiftJIS 関連の定数が定義されており CFStringGetListOfAvailableEncodings を呼び出しても利用可能として入っている (on OSX 10.9) が、どうも kCFStringEncodingMacJapanese しか機能しないのは何か処理が必要なのだろうか?

CFString

 - https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFStrings/introCFStrings.html
 - https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFStringRef/Reference/reference.html

NSString

9
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8