Unicode正規化 その3 (2010.3.22 改訂)

結合文字列は様々な問題を引き起こします。本来は、問題が起こらないようにOSやソフトウェアの側が対応するべきですが、現状ではUnicodeの急進的な規格に技術がそこまで追いついていません。ですから、私たちは自分でなんとかするしかありません。

結合文字列の問題は「1文字なのに複数の文字データになっている」という仕様そのものにあります。この問題を避けるには結合文字列を1つの文字データだけにするしかありません。「結合文字列のポ」を「1つの文字データのポ」に変換するということです。

結合文字列を1つの文字データに変換する

「変換」と言うと、なにかとても難しい処理をするような印象をうけますよね。例えば、なんらかのアルゴリズムに従ってバイナリコードを加工する、みたいな感じです。しかし、結合文字列を1つの文字データにする場合、この方法は使えません。そこにはアルゴリズムがなく、あるのは言語の恣意性そのものだからです。

とはいうものの、やはりコンピュータで処理をするための規格なので、Unicode Consortium は「結合文字列」と「1つの文字データ」の対応関係、つまり「結合文字列のポ」と「1つの文字データのポ」のような恣意的な関係を、属性のひとつとして各文字毎に逐一明記しています。

UnicodeData.txt

このファイルには各文字の属性が列挙されていて、その中に私たちが知りたい対応関係が書かれています。ここから「ポ」の文字を見てみましょう。

 30DD;KATAKANA LETTER PO;......;30DB 309A;......

KATAKANA LETTER PO(カタカナのポ)は
 1つの文字データで「30DD
 結合文字列で「30DB 309A
であることが書かれています。

これから分かることは、ここに書かれている情報に従って「30DB 309A」を「30DD」に置換することで、私たちの目的である「結合文字列を1つの文字データに変換する」ができそうだということです。

そしてこのように UnicodeData.txt の記述に従って置換することが、まさに「Unicode正規化」です。

Unicode正規化

「正規化」とはコンピュータ関連の技術用語で、「ある一定のルールに統一した一貫性のあるデータにする」というような意味です。その方法はデータの使用目的によって様々です。

DTPで例えると、私たちはよくテキストデータを加工して、数字やアルファベットをすべて半角にしたり、約物をすべて全角にしたりします。「一定のルールに統一した一貫性のあるデータ」にしているので、この加工も正規化のひとつであるといえます。

Unicode正規化は、UnicodeData.txt に記されている属性のひとつである「分解マッピング」を一定のルールにして、テキストを正規化することです。この点は非常に重要なことですので、ほんの少しだけ、詳しく見て行くことにします。

ここで、専門用語を3つ覚えてください。

「合成」「分解」「分解マッピング」

私はこれまで「結合文字列を1つの文字データに変換する」と長たらしく書いてきましたが、Unicodeではこれを単純に「合成 Composition」といっています。言葉として「結合」に似ていて紛らわしいのが難点です。
  結合 = バラバラなものがぴったりくっついてかたまっている
  合成 = 化学変化のようにバラバラなものがひとつのものになる
私はこのようにイメージして、混乱しないようになんとか踏ん張っています。

一方、この「合成」とは逆のこと、つまり「1つの文字データをバラバラにして結合文字列にする」ことを、これも単純に「分解 Decomposition」といいます。

そして、UnicodeData.txt で個々の文字に記されている「1つの文字データと結合文字列の対応関係」を「分解マッピング Character Decomposition Mapping」といいます。当然「あ」のようにこれ以上バラバラにできない文字は、分解マッピングになにも書かれていません。

「分解」は、文字をバラバラにするイメージそのままなので一見分かりやすそうですが、実はかなり要注意な専門用語です。

バラバラにならない分解もある

神の旧字体 左の文字は「神」の旧字体です。分解マッピングを見てみます。

FA19;CJK COMPATIBILITY IDEOGRAPH-FA19;......;795E;......

1つの文字データでは「FA19」、そしてなんと、この文字はこれ以上バラバラにはできないのに、分解マッピングに「795E」とあります。795E は新字体の「神」です。これも1つの文字データですから結合文字列ではありません。いったいどういうことなのでしょうか?

実は、「神」の旧字体は分解されると新字体になるのです。

どうしてそうなのかは後述しますが、「分解」という用語は1文字をバラバラにして結合文字列にするだけでなく、別の1文字にする意味でも使われるということを知っておいてください。

さて、専門用語がたくさん出てきましたので、ここで図にまとめてみます。

Unicode用語

他の用語もいくつか追加したいところなのですが、我慢してこれだけにしておきます。

補注1

「1つの文字データ」の専門用語である「合成済み文字」は使わないのかと、不思議に思われている方に向けて書いておきます。

合成済み文字 Precomposed Character」は、たしかに一般的に使われている用語ですが、私がはじめてそれを目にした時、かなり強い抵抗を感じてしまいました。Unicodeでは「結合文字列の方がUnicodeの規格にふさわしい形態であり、音声記号を伴う単一1文字は互換性のためやむなく入れている」ということのようですが、私たちの普通の感覚では受け入れがたいものです。Unicodeに知悉していない状態でこの用語を目にすると、唐突に時系列が逆転して混乱に陥ります。Unicode正規化はただでさえ混乱しやすいので、とにかく混乱を避けるために使うことを回避しました。

内心では、もっと分かりやすい「分解可能な文字 Decomposable Character」か「合成文字 Composite Character」を使いたかったのですが、「分解可能な文字」は先に分解を理解する必要があるので説明の中で使いにくく、「合成文字」は逆の「結合文字列」としての意味で使っている(誤用している)人がかなりいることから、使用を断念しました。

補注2

「アルゴリズムがない」という説明に誤解を招きそうなので、念のために追記しておきますが、アルゴリズムがないのは「ソシュール的な意味での言語の恣意性」であって、コンピュータでの実際の変換処理には当然なんらかのアルゴリズムが使われています。

言い換えると、そのアルゴリズムを構築する前提として、あらかじめ恣意的な対応関係を文字属性として規定しておく必要があり、その「属性の規定」にアルゴリズムがないということです。