Ruby/UTF-2000

Ruby/UTF-2000とはなにか

Ruby/UTF-2000は、XEmacs UTF-2000実装におけるUTF-2000モジュール、
CHISEモジュールのRubyへの移植を試みたモジュールである。

■UTF-2000モデルとはなにか

UTF-2000モデルとは、文字を符号ではなく属性によって扱う方法を意味する。

Ruby/UTF-2000ではそれを拡張し、文字をオブジェクトとして扱っている。

■download & history

  • 2003-0110 テスト公開
  • 2003-0112 XString追加
  • 2003-0115 IDSの読み込み機能β版
  • 2003-0116 IDSの読み込み機能1.0
  • 2003-0117 ruby-utf2000-20030117.tar.bz2
    XStringを廃止し、Stringに一本化。IDSの読み込み機能を強化。
  • 2003-0120 ruby-utf2000-20030120.tar.bz2
    IDS_Treeの読み込み機能を追加。木構造の整合性checkを追加。
  • 2003-0130 ruby-utf2000-20030130.tar.bz2
    IDSの逆変換機能などを追加。

■install

展開して、make installする。

通常、/usr/local/lib/ruby/site_ruby/以下にinstallされる。


■config

src/utf2000.rb

DB_DIR = '/usr/local/lib/xemacs-21.4.10/i686-pc-linux/char-db'
必要に応じて変更する。

IDS_DB_DIR = '/home/eto/work/chise/ids/''
IDSのテキストファイルが置かれているディレクトリーを指す。(下記の字形分解・合成についてを参照)


■依存関係

下記のパッケージが必要。

一般にRubyのパッケージは RAAを使って探すことができる。


■Unicode

現状では、Ruby/UTF-2000に渡す文字コードはUTF-8のUnicodeにしておくと便利である。

これは望ましいものではなく、将来的にはプログラム自体がSJIS、EUCなどで書かれていても 問題なく処理できるようにする予定である。

WindowsでUnicodeを使えるエディターとして、私はMeadow + Mule-UCSを使っている。

他、Windows付属のメモ帳を使うことができる。

また、見るだけであればIEに落すと表示される。

フリーのUnicode対応エディターとして他にYuditがあるが、まだよく使い方はわからない。

■使い方

■全体的な使い方

require 'utf2000'
include UTF2000

str = "字" #Stringを拡張している。UTF8で与えること。
p str.ucs #とすると、その文字のucsの値が表示される
p str.total_strokes #画数が表示される
p str.chinese_gb2312 #などなど
str.char.alist.each {|a, v| #こんな感じで全属性を表示できる
  print a, ': ', v, "\n"
}
p str.inspect_x #Characterについての情報が表示される。
p str.inspect_all #持っている属性情報を全て表示する。

str = "文字列" #もちろん一文字でなく文字列も扱える。UTF-8で与える。
p str.inspect_x #各文字の情報が表示される。
p str.inspect_all #各文字の属性情報を全て表示する。

■様々な用例案

下記のような文章を入力、表示できるようになることを例として考える。

  • 「電話は中国繁体字だと電話と書き、中国簡体字だと電話と書く」
  • 「吉野屋の吉は、土吉の吉である。」
  • 「高橋さんは高橋さんと表記されるのを嫌う。」
  • 「日本語の骨を、中国簡体字だと骨と書く」

が、まだ入力できません。未完成です。

■字形分解・合成

Ruby/UTF-2000は、もともと字形分解・合成を扱うために作られたため、その機能が強化されている。

字形分解・合成は、現在はUnicodeにおけるIDS(Ideographic Description Structure)という仕様に準拠している。 U+2FF0〜U+2FFBで表わされるIDC(Ideographic Description Characters)によって合成方法を指定し、 これに続く二文字から三文字の文字を合成して表示する。

これは元々必要な漢字が文字コードに無い場合にその代替物として表記するために考えられた仕様だ。 もし文字表示機能が字形合成に対応している場合は、その合成された字を表示する。 もし字形合成の機能が無い場合は、IDC自体を目に見えるように表示し、 ユーザーの想像力に任せることになる。

実際のところ、IDSを使った字形合成機能を持つ文字表示エンジンが存在するとは聞いたことがない。 そのため現状ではこの仕様は絵に書いた餅になっている。

ここではその仕様を転用し、漢字の字形を指示するために使っている。

ちょっと想像してみればわかるが、IDSはまともな実装が存在していないことからもわかる通り、 普通には使えない仕様である。実際に漢字の字形を合成して表示するといっても、 縦とか横につらなるなどといった単純な情報だけでは不十分で、もっと多様な情報が必要である。 部品間の大きさのバランスなど、ついheuristicな方法で対処できるのではないかと考えてしまいがちだが、 実際に見ておかしくない字を作るためには現状ではまだ人手によってデザインする必要がある。 ここではその仕様を転じて、字形の成立ちを説明するために使っているが、 このような使い道なら使えるようだ。


■IDSを使うための準備

下記のようにして、IDSのテキストファイル群を持ってくる。

% cd ~/work/chise (このディレクトリーは適宜変更する)
% cvs -d :pserver:anonymous@cvs.m17n.org:/cvs/root login
password: (何も入れずにただもう一度return)

% cvs -d :pserver:anonymous@cvs.m17n.org:/cvs/chise co -d ids ids

このようにすると、IDSのテキストファイル群を持ってくることができる。

その後、src/utf2000.rb
IDS_DB_DIR = '/home/eto/work/chise/ids/''
ここに、上記のIDSテキストファイル群を持ってきたディレクトリーを入れる。 必要であれば、再度make installする。 このようにして適切にIDS_DB_DIRを設定し、 ./tools/idsdbdumpall.rbを実行する。(かなり時間がかかる) これで、文字属性として新たにids, ids-decomposeが加わった。 それぞれ、IDSの文字列、それを再帰的に分解しきったものを意味する。

実用上は差し支えない範囲だが、IDSテキストファイルにはまだ入力されて いない字もある。./tools/idscheckintegrity.rbを実行する(かなり時 間がかかる)と、IDSの木構造の整合性をチェックし、整合性がとれていない字 を表示する。


■字形分解

Stringに、decompose, decompose_allという二つのメソッドがある。 decomposeは一段階だけ分解する。decompose_allはそれを再帰的に行う。

p "字".decompose
p "字".decompose_all
p "榊".decompose
p "榊".decompose_all
p "終了".decompose
p "終了".decompose_all
p "鬱".decompose
p "鬱".decompose_all

最初の説明から、字形分解されて出てきた結果の文字列には、 IDSキャラクターが含まれているため、場合によってはうまく表示されない。 メモ帳だと表示できるだろう。


■字形合成

分解の逆に合成することもできる。ことにしようと思っているが、まだできていない。

■説明

まじめなメソッドの説明を書く。(未完)

class String
	char	先頭の文字をCharacterに変換したものを返す
→method_missingで、存在しないmethodを指定すると、自動的に先頭の文字を
Characterに変換してそれへのmethodとして呼ぶ。

class Character
	get	ある文字をgetする。(flyweightパターン)
	[]	ある属性をgetする。get_char_attributeも使える。
		またmethod_missingも使える。
	[]=	ある属性をputする。put_char_attributeも使える。
		またmethod_missingによる入力も使える。
存在しない属性を参照したときは、nilが返る。

■tools

詳しくはtools/READMEを参照。

  • dbdumpall.rb, char-dbのBDBファイル群の中身をテキストとして展開する。
  • idsdumpall.rb, IDSのテキストファイル群を読みこみ、BDB化する。再帰的に展開したids-decomposeも作る。
  • idscheckintegrity.rb, IDSの木構造の整合性をチェックする。
  • mkdbtarball.rb, UNIXで作ったBDBファイル群をWindowsに持っていくときに使う。 Windowsでtar.gzを展開するには、eoがおすすめ。
  • trim_bom.rb, Unicodeファイルを作ったときの先頭についてくるBOM(byte order mark)を削除する。

■悩みどころ

iso-2022へのencodeはどう実現すればよいのか?
Characterはどうencodeするかの属性を持っていて、 XStringはその実際のencodeの処理を行うという分離でいいかな。
iso-2022-jpの処理はどうすればいいのか?
iso-2022-jpは行末ではASCIIに戻すという行単位の扱いが必要になるが、 XStringの中からはその判断はできない。 class IOを拡張するのがいいのか?

■字形合成

"+木木"(+はU+2FF0を意味する)という文字列が あるとして、しかしこれは実は"林"という一文字を表している。 この二重性をどう取り扱うか?
newされた時点で問答無用で"+木木"を"林"というCharacter一文字に変換 してしまうと、その時点で区別ができなくなってしまう。つまり必要に応じて composeするべきである。しかしその必要に応じてというのはどのように判定 すればいいのだろうか? 明示的に指定するしかないということか。
Unicode対応のeditorはどうとりあつかっているのだろうか? Unicodeの規定によれば、このIDSによって指定された文字列は、合成された文字そのものを 表すと規定されている。合成された文字を表示可能である場合は、IDS自体を表示してはいけない。 逆に合成した文字を表示できない場合は、IDS自体を見えるように表示しないといけない。 とすると、Unicode対応のeditorが適切な文字合成の機能を持っていた場合、 それは合成された結果の文字を表示するのがいいのか? 合成される前の文字列を 表示するのがいいのか? 結局ユーザーが明示して切り替えられるようにするのがいいのか?
もしエラーが含まれていた場合は?
"+木".to_x.compose_ids とした場合は、オペレータの対象が一文字しか無いので、処理できない。 これは例外をraiseするか、元の文字列をそのまま返すか、悩みどころ。
もし文字が存在しなかった場合は?
"+林林"とかした場合は、"木"が横に四つ並んでる漢字は存在しない(と思う)ので、 これも例外とするか、元の文字列をそのまま返すか悩みどころ。 どの文字コード体系にも存在しないような文字を表示できる字形合成エンジンがあると 仮定して、そのエンジンに手渡されるまでは、情報が失われないように処理 するべきである。
また、本来UTF-2000モデルはこのような「存在しない文字」をとりあつかえるように するためのモデルなので、こういった文字もシームレスに扱えるようにするべきである。 しかしどのようにすればいいのかわからない。

■Ruby/M17Nとの整合性

Ruby/M17Nとの整合性をどうとればいいか。

Ruby/M17Nブランチが本体に反映されるのは、ruby-1.8以降が予定されている。

ソースコード中のm17n.c, m17n.hが該当個所。 UTF-2000は内部的にはUTF-8として扱えるので、それを拡張すればいいか? UTF-8の処理への追加という形で実装できる?

■CHISEvis project progress report

Ruby/UTF-2000作成プロジェクトはCHISEプロジェクトの可視化サブプロジェ クト(CHISEvisと呼ぶ)の一環として行われている。ちょっと文脈がずれちゃう のだが、CHISEvisのおおまかな進行状況もここに書いておく。後でちゃんとペー ジは独立させるつもり。

CHISE漢字間構造の可視化は様々な目標を設定しているが、 その様々な目標の全てにおいて共通する構造がある。 可視化はおおまかに二つの部分にわけることができる。 一つは漢字構造を処理するエンジン部分、もう一つは漢字の部品を指定・表示するインターフェイス部分である。

  • 漢字を構成する部品をいくつか指定し、その指定された部品から合成できる漢字を計算するというエンジン部分
  • その部品を指定し、選んだ結果の漢字を表示するというインターフェイス部分

この二つを切りわけた設計にすることにより、 エンジン部分の動作を切り替えることにより複数の目的を満すことができるようになる。

エンジン部分のヴァリエーションについていくつか具体例をあげる。

  • 合成される結果の文字を小学校で習う1006字だけに制限することにより、 小学生対象の漢字学習ソフトとして機能するようになる。 部品の合成によって漢字の成立ちを学習することができる。(漢字博士のようなソフト。)
  • JISX0208集合を対象とすることにより、おおまかに現在日本で一般に使われる漢字集合を対象とした 漢字構造の検収をすることができる。
  • 篆書(または甲骨文字)との関連データを加えることができれば、 漢字の字源にさかのぼって、関連性を見ることができる。
  • もちろん対象をデータベース中の全漢字とすれば、 現在保持しているデータの整合性などを検収することができる。
  • 合成される結果をJIS漢字集合、補助漢字、Unicodeなどの区分にわけて分類し、 それぞれを色分けなどで識別できるようにすると、部品正規化などの正規化を 見てわかるようにできるかもしれない。

インターフェイス部分のヴァリエーションについては未定であるが、 現在はマウスによるインターフェイス、画像入力によるインターフェイスを考えており、 その二つは共通のバイナリーとして構築されることを考えている。 もっとアドバンスなインターフェイスも可能であるが、要求に答える形で 実装することを考えている。

1月中にエンジン部分を完成、2月中にインターフェイス部分を完成、 というおおまかなスケジュールを考えている。 現在ほぼスケジュール通りで進んでいるが、予想以上にエンジンが面倒で、 インターフェイス設計がまったく進んでいない。 (しかし関係無いとはいえ、シンポジウムの開催時期を考えればスケジュール はもっと前倒しであるべきだったと反省している。)

■IDSデータの問題点

個々の漢字ごとにIDSがデータ化されており、これを使えば簡単に部品ごとの データを使えるようになるだろうという見積りだったが、実際はデータの処理 に様々な工夫をこらす必要があった。

→IDSエラーの排除

IDSが入力途中の文字には、不明部品の代りに?が入っている。 IDSの構造が正規化されていない。Tree情報にならなくてはならないのだが、 部品が足りない、部品が余る、自分自身を含んでいるなどのエラーがあった。 jisx0208集合ではエラーは一つだけだったため、大きく問題にはならないと判断し、 まだエラーは修正していない。

→複数候補の問題

IDSの逆変換をするときに、複数候補が生じることがある。 その複数候補の中には、attributeを持っていないものもある。 これがisolated character, builtin characterと呼ばれるものと同一かどうかは よくわからない。こういった属性を持たぬ文字がどのようなメカニズムでまぎれこむ ことになるのかもよくわからない。現在はこのような情報は排除している。 それでも複数候補は残る。だいたいは違う文字集合に属する漢字であり、 それがIDSの表現力の限界で同一候補になってしまったようだ。

またJIS73, JIS83との違いで食い違うこともある。これは字形変化が原因であるが、 このような場合には、IDSという個々の部品に分解された状態においても、 字形の違いの情報が保存されていてしかるべきだろう。 このようなデータも、今はまだ修正していない。

■IDSデータ整備

下記にIDSをどのように操作したかを簡単に記録する。

→元のIDSテキストデータを読み、なにもデータを編集せずに char-db/idsとしてデータをBDB化する。 実体参照で参照された文字は、MCSに変換する。

→次に、エラーを含むIDS、対象となる文字が属性が無いものを排除し、 char-db/ids-normalizedとしてBDB化する。

→それを元にそのids-normalizedの逆変換としてids/char-bdを作成する。 逆変換は複数候補の可能性があるため、返ってくるデータは複数文字の可能性がある。

→そのデータを元にして、IDS Treeの部分集合を他の文字一文字に集約することが できるかどうかを計算し、それを個々に計算した結果である char-id/ids-aggregated, その逆変換 ids-aggregated/char-id を作成する。 集約する計算の際に複数候補の問題が生じる。

ここでは複数候補が生じてしまう場合には、どの文字に集約されてしまったのかによって 情報が失われる可能性があるため、集約しない。 このような文字は○○文字である。

→部品を再帰的に分解していき、分解されきった状態というデータは、 簡単に計算可能であるのでBDBとしては用意しない。

→ids-aggregatedを元にして簡単な統計をとる。 IDSが定義された全字数 IDS Treeのdepthがどのくらいか。 最も深いdepthが4となる。 つまり集約した結果となる漢字はかなりdepthは少なくなる。 突出して複雑に合成された漢字というのはあまりなく、 つまり、それぞれの漢字を分解した部品だけとりだした字も大抵の場合は 存在するということがおおまかに説明できるだろう。

→この状態で、次に部品毎の計算を行う。 ids-aggregatedを元にして、それが含む部品点数をArray化する。 そしてそれをさらに再帰化し、それぞれの部品においても部品をArray化する。 それを一つのArrayに集約し、sort, uniqする。このようにして、 再分割されたものも含む部品の列が取得できる。 これを、char-id/ids-partsとして、文字ごとに部品列を持つ。

次にその部品列を分解して、部品ごとにそれを部分として持っている漢字の 列をだす。それをchar-id/ids-containedに保存する。

→ここまでできれば、ids-containedを元にして、二つの列の共通集合をとる という操作をすることによって、目的とする文字が得られる。

2002-01-29: 現在はids-partsのBDBを作成するところまで出来ている。 ちょっと作業がとまりそうなので、現状でまとめておく。

■UTF-2000モデルへの疑問

私がUTF-2000モデルにいだいている疑問は、結局のところ「文字とは何か」と いう問題についてなんら明確な定義がされていないということだ。

UTF-2000モデルは属性によって文字を指定する方法ということになっているが、 実際のところそこで属性として扱われているのは結局のところ、 「JISX0208において0x3B7Aという番号で指定された文字」というような形の 属性によって文字を指定することがほとんどである。一体これを属性によって 文字を指定する方法と言っていいのかどうか、非常に疑問である。

そしてまた、現在のUTF-2000実装では、ある文字がJISX0208という集合の属す る文字として指定したという情報はここでは失われてしまっている。日本語、 中国語にある文字は、字形が同じであるとされている場合は、unifyされてし まう。これはもちろん標準文字データベースの問題であるが、このように 文字集合をそれぞれまったくunifyせずに扱った場合、データベースを持つ 意味は非常に低くなる。

もちろんUTF-2000モデルであるから、その場その場において、各自使用者が、 自分なりに定義した文字を使用することができる。しかしそれを外部化し、 セーブするときには既存の文字集合にしばられることになる。 既存の文字集合にマッピングできなかった場合は、&MCS-xxxxxxxx;という 実体参照で指定されることになるが、これが情報交換に不適当なのは 自明である。

逆に言えば、既存の文字集合のどこにも属さない文字をどのように外部的に指 定するのかの方法についてはなんら議論されていないようである。

属性によって指定された文字を、属性によって指定されたままの状態で 指示しつづけることはできるのか。 実際のところ現在のUTF-2000実装はその問題を回避している。

私がこの問題を解決する手法として提案するのは「S式が使える実体参照」で ある。これを「属性参照」という名前で呼ぶことにする。

現在は属性によって文字を指定する方法としてchar-definitionによってemacs lispから文字を定義する方法がある。これはシステム上で実行されるプログラ ムとデータとが分離されている状況で可能なことであって、外部化されたデー タにはそのようなプログラムの実行情報は保存されない。属性参照は、簡単に 言えばそのプログラムの実行状態をデータ内部に内包可能とするものである。

例えば現在のUTF-2000実装において、JISX0208の0x3B7A番で指定される文字の 実体参照は下記のような形式となる:

&J90-3B7A;

これを拡張して、例えば下記のような指定方法ができるようにする:

&(japanese-jisx0208 . 0x3B7A);

これを応用すれば、例えば画数が6で、部首がウカンムリである文字は 下記のように指定できる。

&(total-strokes . 6)(ideographic-radical . 39);

もちろんこの場合は複数候補が生じてきてしまうので、それのどれを指してい ることにするかはまだ疑問が残る。

もちろんこれは「プログラムの実行」以外の何ものでもないので、 実際には様々な問題が生じるだろう。 セキュリティの問題などは忘れずに対応しておくべきである。 例えば対象となる文字が一つに特定できない可能性がある。 しかしそれももちろん指定可能とするべきである。 つまり「一意に特定できない文字」というのを指定したと解釈するべきである。 それをどう表示していいのかは、まったくわからないのだけど…。

■固有名

文字を本当に属性参照の束によって指定することができるのだろうか。 私はこれは大いに疑問であると思っている。 つまり、文字は属性参照の束には還元できないのではないかと思っている。 文字とはそれぞれがすでに固有名となっているのではないだろうか。

これは哲学における固有名の議論にほぼそのまま対応する。 固有名とは属性参照の束に還元されないそれそのものとしてしか参照しえない 名前を意味する。

一般言語学においては言語をそのような固有名から切り離された構造の集合に 還元してとらえるが、実は実際のところ個々の言語は固有の言語としてしか 存在しえず、言語間の要素を共通してとらえる一般言語のようなものは存在しない。

特殊名、一般名との区別も重要。特殊名であることは、一般名であることの 特殊形態であると考えられるが、それはつまり一般的にとらえられる特徴の 要素の集合としてとらえられるので、属性参照によって指示できる文字というのは 一般名の特殊形態である特殊名であるととらえられる。

この漢字のおける文脈をあてはめてみて考えると、 一般名とはjapansese-jisx0208集合に含まれるものという記述で、 特殊名とはその集合において12266という数字で指定されるものという記述に 対応するのだろうか。それに対して、それぞれの漢字はそれそのものが 固有名であると考えると「字」は「字」であること以外の何ものでもない、 ということになる。

ここでは同一性をどのようにして判定するかが大きな疑問となる。 jisx0208集合の文字と、chinise-big5集合の文字とが本当に同じ文字なのかどうか。

■ヴェニス・ビエンナーレ 第8回 建築展

岡崎乾二郎氏がディレクターをつとめ、 ソウル、北京、ハノイ、京都の四人の建築家が参加したこの建築展のテーマは、 『漢字文化圏における建築的言語の生成』だそうだ。

http://www.jpf.go.jp/j/others_j/whats_j/0208/08-05.html

セゾンアートプログラムにおいて行なわれた松浦寿夫との議論において、 この建築展のテーマを漢字文化圏と設定した意味を語っていたそうだ。

漢字とアルファベットの関係。漢字は固有名である。 複数の部品が並置されることのより意味が生じるという特殊な形態。 ベトナムではチェノムという新字体系が作られた。

詳細を調べたいと思っているところ。

Kouichirou Eto, 2003 at eto.com