Unicodeの正規化

kyuka様のリクエストにより,Unicodeの正規化の話を(遅れてすみません).真面目に書くと論文になってしまいそうなので,ほんのさわりだけだが.


Unicodeは,ある文字を表すUnicode文字シーケンスがユニークに決まるとは限らない.たとえば,アクセント付き英字は,合成済み文字として表されることもあれば,英字とアクセントの文字合成シーケンスとして表されることもある.これでは,当然文字列の比較や検索に支障があるので,文字シーケンスを一旦正規化してから比較や検索をおこなう.この操作を,正規化(normalization)と呼ぶ.


さらに,ある文字が複数のコードポイントに重複して符号化されていることがある.これは,各国の文字の規格で区別されている文字は,Unicodeでも区別するという源規格分離規則(source separation rule)を採用しているからだ.そこで,このような文字をも同一とみなす正規化手段も提供している.たとえば,いわゆる全角文字と半角文字は,これでは同一とみなされるなど,情報検索などにおいては利点も多い.


また,正規化方法は,大きくわけて,文字をできる限り分解する方法(decomposition,NFDとNFKD)と,逆にできる限り合成する手法(composition,NFCとNFKC)の2種類がある.Unicodeは,バージョンごとに収録文字数が増えていくために,NFCとNFKCはバージョン間の互換性がないことが問題であったが,これは文字合成をおこなう時のバージョンをUnicode 3.1.0に固定することによって回避した.

より詳しい情報については,Unicode Consortiumの次のTRやFAQを見て頂きたい.


http://www.unicode.org/faq/normalization.html
http://www.unicode.org/reports/tr15/


現在,Javaでは,java.text.Collatorクラスおよびjava.text.CollatonKeyクラスがUnicodeの正規化を処理する.しかし,これはStringを比較するためのものであり,全文検索などのより複雑なテキスト処理をおこなうアプリケーションでは使用できない.そこで,このような場合は,IBMが無償で公開していたnormalizerを用いていた.しかし,初期のライセンスの問題などから自由に配布できず,たとえばLucene-jaの実装では,重要性を知りながらも,あえて正規化をしていなかった.しかし,標準で提供されれば,これは容易におこなえる.


さらに,文字合成のバージョンを固定したことから,NFCやNFKCの適用範囲が広くなり,WebやXMLでは,NFCとして正規化済みのテキストを対象とする方向に進みつつある.また, MacOS Xのような高度のレンダリングエンジンをもつ環境では,ソフトウェアキーボードで入力した文字は文字合成シーケンスとしてメモリ上に保持されるなど(当然正しく表示できる),常に文字が合成済みであるという仮定も成り立たなくなってきている.つまり,今後はより一般的なプログラムでもUnicodeの正規化処理が必要になるだろう.


そこで,Javaに正規化対応を要求するのが,次のRFEである.


http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4221795


ただし,残念ながら,日本語においては困った問題がある.というのは,互換漢字に属する一部の文字は,正規化処理をしてしまうと,対応する統合漢字に変換されてしまうからだ.つまり,正規化をおこなうと,「各国の規格で区別されていた文字が区別できなくなる」,「可逆変換ではなくなる」のだ.Unicode Consortiumでも,この問題が認識されていたが,この問題を解決するための提案は却下されてしまったようだ.詳しくは,次のページを見て頂きたい.


http://homepage1.nifty.com/nomenclator/unicode/normalization.htm


そこで実際にMacOS XファイルシステムHFS Plusでは,ファイルシステム上でこれらの文字も区別するためにModified NFDでファイル名を格納している.私は,MustangにおけるJavaの正規化クラスにおいても,この問題を検討しなければならないと考えている.


というところで,よろしいでしょうか?>kyuka様(なにしろ,今週は毎日飲み会なので…)