Q: Unicode 文字列を合成済みの文字の形式に変換する方法はありますか?
A: Mac OS X 10.2 で導入された API を使用して、文字列を合成済みの Unicode に変換できます。以下に、合成済みの Unicode と分解された Unicode の違い、なぜ合成済みの Unicode に変換する必要があるのか、および変換方法について説明します。
合成済みの文字と分解された文字
特定の Unicode 文字は、複数の方法でエンコードできます。たとえば、Á(A アキュート)は、U+00C1 (LATIN CAPITAL LETTER A WITH ACUTE) のような合成済みの文字、または U+0041 U+0301(LATIN CAPITAL LETTER A に続く COMBINING ACUTE ACCENT)のような分解された文字のいずれかをエンコードできます。Windows 環境では合成済みの文字を使用するほうが一般的ですが、Mac 環境では分解された文字のほうが一般的です。
Mac OS で作業をしていると、合成済みの Unicode と分解された Unicode の組み合わせを使用していることに気づきます。たとえば、HFS Plus は、ファイル名をすべて、分解された Unicode に変換します。一方、Macintosh のキーボードは、一般に合成済みの Unicode を生成します。これは、システムが提供する API を使ってテキストを処理している限り、問題ではありません。アップルの API は、合成済みの Unicode と分解された Unicode の両方を正常に処理します。
しかし、Macintosh 以外のプラットフォームとやり取りする場合は、合成済みの Unicode に変換する必要があるかもしれません。たとえば、次のような場合はすべて、合成済みの Unicode に変換する正当な理由になります。
- 合成済みの Unicode を使用するように定義されたネットワークプロトコル実装する場合。
- 合成済みの Unicode を使用するように定められたクロスプラットフォームファイル(またはボリューム)を作成する場合。
- 合成済みの Unicode を期待している大量のクロスプラットフォームコードをアプリケーションに組み込む場合。
|
重要: テキスト処理を簡単にする目的で合成済みの Unicode に変換するのは避けてください。合成済みの Unicode 文字は、依然として合成文字を含んでいることがあります。たとえば、U+0065 U+030A(LATIN SMALL LETTER E に続く COMBINING RING ABOVE)に相当する合成済みの文字はないため、合成済みの文字へ変換するのはまったく意味がありません。 |
Unicode コンソーシアムの Web サイト に Unicode に関するさまざまな情報があります。特に興味深いのは、Unicode Standard Annex #15 の Unicode Normalization Forms です。この Q&A で使用しているように、合成と分解という用語は、それぞれ Unicode Normal Forms D (NFD) と C (NFC) に対応しています。
Mac OS X 10.2 での合成済みの文字への変換
Mac OS X 10.2 では、Unicode 文字列を合成済みの文字の形式に変換する 2 つの API が導入されています。最も簡単なのは、CFStringNormalize です。リスト 1 に、この関数のプロトタイプを示します。<CoreFoundation/CFString.h>ヘッダファイルのコメントを読むと、CFStringNormalize の詳細をより深く理解できます。
typedef enum {
kCFStringNormalizationFormD = 0,
kCFStringNormalizationFormKD,
kCFStringNormalizationFormC,
kCFStringNormalizationFormKC
} CFStringNormalizationForm;
void CFStringNormalize(CFMutableStringRef theString,
CFStringNormalizationForm theForm);
|
|
リスト 1.
CFStringNormalize のプロトタイプ |
さらに、Mac OS X 10.2 の Unicode Converter を使って、Unicode 文字列を合成形式に変換できます。リスト 2 のコードにこの方法を示します(precompose パラメータには true を渡すものと想定しています)。
static OSStatus ConvertUnicodeToCanonical(
Boolean precomposed,
const UniChar *inputBuf, ByteCount inputBufLen,
UniChar *outputBuf, ByteCount outputBufSize,
ByteCount *outputBufLen)
/* Unicode Converter の規格に従って、長さはすべてバイト数 */
{
OSStatus err;
OSStatus junk;
TextEncodingVariant variant;
UnicodeToTextInfo uni;
UnicodeMapping map;
ByteCount junkRead;
assert(inputBuf != NULL);
assert(outputBuf != NULL);
assert(outputBufLen != NULL);
if (precomposed) {
variant = kUnicodeCanonicalCompVariant;
} else {
variant = kUnicodeCanonicalDecompVariant;
}
map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
kUnicodeNoSubset,
kTextEncodingDefaultFormat);
map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
variant,
kTextEncodingDefaultFormat);
map.mappingVersion = kUnicodeUseLatestMapping;
uni = NULL;
err = CreateUnicodeToTextInfo(&map, &uni);
if (err == noErr) {
err = ConvertFromUnicodeToText(uni, inputBufLen, inputBuf,
kUnicodeDefaultDirectionMask,
0, NULL, NULL, NULL,
outputBufSize, &junkRead,
outputBufLen, outputBuf);
}
if (uni != NULL) {
junk = DisposeUnicodeToTextInfo(&uni);
assert(junk == noErr);
}
return err;
}
|
|
リスト 2. Unicode Converter を使用して合成済みの Unicode を作成する方法 |
このコードついて、次の 3 点に注意してください。
precompose パラメータに false を渡すと、分解された Unicode 文字を作成できます。
- このコードでは、
ConvertFromTextToUnicode ではなく、ConvertFromUnicodeToText を使用します。Unicode 以外の文字コードから直接合成済みの Unicode に変換することはできません。
- このコードでは、Text Encoding Converter (TEC) ではなく、低レベルの Unicode Converter を使用します。TEC は、合成済みの Unicode への変換をサポートしていません。
文字コードが Unicode 以外の任意の文字列を合成済みの Unicode に変換するには、A) その文字列を(Unicode Converter または TEC を使用して)Unicode に変換し、次に、B) その Unicode を(上記のコードを使用して)合成済みの Unicode に変換する必要があります。
|
注記: Unicode 文字に変換するときに、TEC は、ソースの文字コードの合成/分解の特性を保持します。たとえば、MacRoman は分解された文字をサポートしていないため、TEC はデフォルトで合成済みの Unicode を生成します。これに対して GB 18030 は分解された文字をサポートしており、TEC はこれを分解された Unicode 文字として保持します。このため、ソーステキストの文字コードの特性が分かっている場合は、これを使用して上記の B の手順を回避できます。 |
以前のシステムでの合成済みの文字の変換
上記の解決方法は、Mac OS の以前のバージョンには適用されません。Mac OS X 10.1.x 以前の環境で合成済みの Unicode に変換する必要がある場合は、独自のコードを記述する必要があります。International Components for Unicode(Unicode の国際化を目的とした IBM のオープンソースコード)で提供されている正規化関数の使用を検討してください。
[2003 年 2 月 7 日]
|