MuTerminalにおける文字幅の決定方法について

単なるエディタとは違い、端末エミュレータでは文字の幅は固定でなければいけません。一般的には、欧米諸国の文字は文字の横幅が高さの半分である半角文字が使われ、日本などの極東地区の文字(漢字、かな、ハングル)では、幅と高さが同じ全角文字が使われます(ただし半角カナ文字を除く)。

一方、BeOSの内部文字コードとして使われるUnicodeでは、全角、半角という概念がそもそもありません。ただし、従来の文字コードとの互換を考慮して、文字幅の定義としてHalf,Narrow, Full, Wide, Ambiguousという4つのカテゴリを定義しています。このうち、HalfとNarrowは半角、FullとWideは全角として処理できますが、Ambiguousは、半角全角、どちらともとれる文字幅として定義されています(参考:ユニコードコンソーシアムホームページ)。

たとえば、ギリシア文字のαは、ISO-8859-7(Latin/Greek alphabet)ではコードポイント1/14、JIS X 0208では、コードポイント06/33で定義されています。ISO-8859-7は半角文字集合であり、JIS X 0208は全角文字集合です。

一方Unicodeでは、このように異なる文字集合に異なる幅で登録されている文字が、同じコードポイント(0391)に置かれ、Ambiguousカテゴリとして定義されているのです。

このように同じ文字がフォントによって違う幅として登録されているフォントの文字幅をMuTerminalでは以下のようにして扱います。

設定されている文字コードがUTF8の場合。

端末の表示文字コードがUTF8に設定されている場合、MuTerminalは既存の文字集合とUnicodeとの変換テーブルを、以下の優先順位にしたがって逆引サーチを行います。

ascii --> latin-iso8859-1 --> latin-iso8859-2 -->
latin-iso8859-3 --> latin-iso8859-4 -->
cyrillic-iso8859-5 --> greek-iso8859-7 -->
hebrew-iso8859-8 --> latin-iso8859-9 -->
japanese-jisx0208 --> japanese-jisx0212 -->
chinese-cns11643-1 --> chinese-cns11643-2 -->
chinese-cns11643-3 --> chinese-cns11643-4 -->
chinese-cns11643-5 --> chinese-cns11643-6 -->
chinese-cns11643-7 --> chinese-gb2312 -->
korean-ksc5601 -->
katakana-jisx0201 --> latin-jisx0201
(ISO-8859-6,10は上記のテーブル中にありませんが、半角で処理されます。ver 1.1からKS C 5601もサポートしています)

前述のαの場合、上記優先順位でサーチすると、最初にISO-8859-7で引っ掛かります。ISO-8859-7は半角文字集合ですから、出力される文字は半角となります。なお、この優先順位はGNU Emacs上でUTF8/Unicodeを扱うためのパッケージ、Mule-UCSのデフォルトです。すなわち、GNU Emacs + Mule-UCS + MuTerminalという組み合わせであれば、表示されている文字幅とGNU Emacsが処理する文字幅(lisp function (string-width)の値)の整合はとれるわけです。なお、Mule-UCSでは、この優先順位をEmacs-lispを書き換えることによって変更できますが、MuTerminalではテーブルを作り直して再コンパイルしないがぎりできません。

なお、変換テーブルはUTF8FontWidth.cで定義されており、優先順位を変更したい場合は、GNU Emacs + Mule-UCSで、付属のcalc-font-width.elとutf8.txt、UTF8FW_Tamp.cをロードし、lisp関数calc-font-widthを実行することによって生成されるファイルを使って再コンパイルします。

設定されている文字コードがUTF8以外の場合

UTF8以外の文字コードの場合、その設定されている文字コードから文字幅を算出できます。ISO-8859系であれば、半角であり、EUC, SJISなどの日本語文字コードの場合、JIS X 0201なら半角、JIS X 0208とJIS X 0212なら全角という具合に文字幅を算出できます。文字コードがEUCやSJISの場合、αは全角文字集合JIS X 0208であるため、全角として表示されます。もちろん、GNU Emacsもset-terminal-coding-systemにSJISやEUCが設定されている場合、αを全角として取り扱うため、問題なく表示できます。

この2通りの方法によってMuTerminalは文字幅を確定します。少なくとも、GNU Emacsを使用するかぎり、MuTerminalは実際に表示される文字の文字幅とEmacsが内部で扱うstring-widthとの整合がとれるわけです。逆に、その他のアプリケーション、たとえば単純にcatコマンドの出力でも、MuTerminalが設定している文字コードによって、同じ文字が違う幅(あるいは違うフェイス)で表示されることになることに気をつけておいて下さい。また、MuTerminal上で動作するアプリケーションを作成する際は、この特性を念頭に置いて置く必要があります。

追記:

ただし、実際には端末コードUTF8として、αを表示させると、四角い箱が表示されるはずです。これは、BeOSに標準で添付されるフォントでαが登録されているのがHaruとHaru Tohabaだけだからです。一方、MuTerminalは前述の方法によりαは半角と判定し、半角に設定されているフォント(デフォルトではCourier10 BT)で表示しようとするからです。半角フォントをHaru Tohabaにすれば、表示はできますが、Haru Tohabaはαを全角フォントとして登録してあるため(これはHaruが日本語フォントだからです)、今度は表示がおかしくなります。これは、BeOSに添付される欧米フォントに収録されている文字が少ないのが原因です。

BeOSで確実に収録されている欧文文字集合はISO-8859-1のみであり、2〜10は一部、あるいは全部の文字フェイスが欠落しています。このためMuTerminal(デフォルトのTerminalも同様)がISO-8859-2〜10に対応していても、実際に表示することはできません。もし、このような問題を回避したい場合、その文字があなたの期待する文字幅でしかも等幅で収録されたフォントを探すしかありません(参考:マイクロソフトフォントパックホームページビットストリームサイバービットホームページ)。

さらに、半角カナについては、現在サポートしていません。これは、半角カナが半角フォント(通常は欧文フォントを指定しているはずです)で表示されてしまうからです。これを特別に回避するルーチンを現在作成中です。

また、GNU Emacsでは、バッファ内で多国語を扱うため、文字ごとにその文字がどの文字集合であるか、どこの国の言語であるかを指定できます。このため、MuTerminalの文字コードとEmacsのset-terminal-coding-systemをUTF8に設定し、GNU Emacs上でEmacs-Cannaなどを用いてαを入力すると、それは前述の通り半角として表示されるにもかかわらず、全角文字のように扱われます(すなわちカーソルを移動すると、2文字分移動する)。これはEmacs-Cannaが日本語を入力するためのパッケージであり、Emacs-Cannaの出力は日本語の文字集合JIS X 0208やJIS X 0212に属するという前提によって処理が行われるからです。次に、このファイルをUTF8コーディングで保存し、再度開くと、今度は半角として表示され、半角として処理されます(ファイル保存時に、ISO-2022形式で保存するか、地域に依存する文字コードで保存しないかぎり、文字がどの地域の言語であるかという情報は失われれるからです)。このような問題を回避するにはMuTerminalの文字コードをあなたの国で一般的に使用される文字コードに変更するか、MuTerminalの内部コードがISO-2022に対応するのを待つしかありません(ただし、処理速度や実装の難易度の観点からMuTerminalの内部バッファコードがISO-2022になることはおそらくありません)。いずれにしてもUTF8コードを使用するかぎり、かならずしもAmbiguousカテゴリの文字幅が適切に処理される保証はありません。なにしろAmbiguousなのですから......

Unicodeと既存日本語文字集合との変換について

UTF8以外の文字コードの場合については、上記のように処理するにも関わらず、実際にはいくつかの文字の幅がおかしくなったり、文字が表示されなくなります。

たとえば、JIS X 0208の全角の£(POUND_SIGN)は、BeOSが提供するconvert_to_utf8でUTF8に変換すると半角に変換されます(Narrowのカテゴリにあります)。これは、Unicodeコンソーシアムの変換テーブルがそうなっているからです。FULLWIDTH_POUND_SIGNという文字が拡張領域にありますが、Unicodeコンソーシアムが用意しているJIS X 0208<->Unicodeの変換テーブル上にはこの文字への変換テーブルがありません(GB2312の方にはあるんですが・・・)。このため、逆にUTF8の全角の£をSJISなどの文字コードに変換するとテーブル上に文字がないため変換不可能となり、半角の'?'になります。このような文字はまだいくつかあります(¢、\など。どれくらいあるか正確には把握してません)。

MuTermialは文字コード変換をしても表示だけしか行わないため、勝手に変換テーブルを変更してしまっても良いのかもしれませんが、今のところそのようなややこしく、かつトラブルの元になりそうなことはしていません。このため、£は半角で表示されます。ただし、上記の通り、UTF8以外の文字コードの場合は文字集合から幅を算出しますので、桁送りは全角で行われます。つまり、表示上半角になることがあっても、処理上では全角として扱うため、これらの文字のせいでスクリーンエディタ等の表示がおかしくなることはありません。

なお、このような既存文字コードとUnicodeの変換は、Unicodeを利用しているシステム(Windows NT, Mac OS 8.5, Java等)によって、それぞれ若干異なる変換を行っているため、これらの文字を利用する場合は十分注意が必要です。


MuTerminal Help File : width.html,v
Last modified : 1999/10/02 15:10:38