2009년 11월 27일 금요일

既存の日本語文字コードと Unicode の間のマッピングルール

既存の日本語文字コードと Unicode の間のマッピングルール


目次


はじめに

Qt 2.0 に既存の日本語文字コードと Unicode の間の変換クラスを突っ込もうと思って調べはじめたら想像以上にややこしいことになっていてはっきり言ってお手上げ状態なんですが、とりあえず調べたところまではまとめておくかな、ということでページを作ってみました。こんなものでも何かの参考になれば幸いです。

ここでは ASCII, JIS, EUC, ShiftJIS, Unicode について知っていることを前提としています。

このページでは 0x1234 のように書いてあるものは既存の文字コードを 16 進数で表したもの、 U1234 のように書いてあるものは Unicode を 16 進数で表したものです。 通常は Unicode は U+1234 のように書くんですが、最初に図を書く時に U1234 って書いちゃって修正するのが面倒なのでこれで行きます(^^;。

抜けや間違い等を発見した場合は hc3j-tkg at asahi-net.or.jp までご一報下さいm(_ _)m。


関連リンク

関連雑誌記事

  • ASCII 1998年6月号 P.269-275 「漢字文化は危なくない」
  • ASCII 1998年12月号 P.477-481 「Unicode を巡る放談会」

参考文献


Unicode-1.1 : ASCII <-> Unicode

まずは ASCII コードについてですが、これはなんてことはなくて、 0x20~0x7e まで (制御コードも含めると 0x00~0x7f まで) がそのまま U0020~U007e (U0000~U007f) にマップされます。


Unicode-1.1 : JISX0201, JISX0208, JISX0212 <-> Unicode

次は Unicode 1.1 の仕様に従った場合の JISX0201, JISX0208, JISX0212 のマッピングですが、JISX0208, JISX0212 については順不同で Unicode にマップされるので詳細については省略します。ここでのポイントは以下の点です。
  • JISX0201 の 0x20~0x7e まで (制御コードも含めると 0x00~0x7f まで) は、二つの例外を除いて、ASCII と同じく U0020~U007e (U0000~U007f) にマップされます。
  • JISX0201 の 0x5c は ASCII の 0x5c と違って U00a5 (Yen Sign) にマップされます。
  • JISX0208 の 0x2140 ('\') は U005c (Reverse Solidus) にマップされます。
  • JISX0201 の 0x7e は ASCII の 0x7e と違って U203e (Overline) にマップされます。
  • JISX0212 の 0x2237 ('・') は U007e (Tilde) にマップされます。


日本語 EUC の問題

さて、Unicode-1.1 のマッピングルールに従った場合、JISX0201 + JISX0208 である ShiftJIS を Unicode に変換するのには特に問題はありません。しかし、ASCII + JISX0201 Kana + JISX0208 + JISX0212 である日本語 EUC を Unicode に変換しようとすると下の図のように U005c と U007e で衝突が起こってしまします。この時点で既に Unicode-1.1 の規格では問題があって、既存の日本語文字コードを扱うには不十分だと言えます。そこで、この問題をどうやって回避するか、なんですが…これが困ったことにプラットフォームによって様々なのです。


オープングループ日本ベンダ協議会CDE/Motif 技術検討 WGUnicode とユーザ定義文字・ベンダ定義文字に関する問題点と解決策 を公開しています。その コード変換規則 について見てみます。

JISX0221-JISX0201

JISX0221 で 0x20~07e を JISX0201 とみなす場合のマッピングルールで、事実上、ShiftJIS <-> Unicode 用のマッピングルールでしょう。 Unicode-1.1 とは 0x213d ('―') が U2015 (Horizontal Bar) ではなくてU2014 (Em Dash) にマップされる点だけが異なっています。 私にはどちらが好ましいのかは分かりません。 というか、どっちでも良いから一つに決めてくれ、というか。

JISX0208 Unicode-1.1 JISX0221-JISX0201
0x213d ('―') U2015 (Horizontal Bar) U2014 (Em Dash)


JISX0221-ASCII

JISX0221 で 0x20~07e を ASCII とみなす場合のマッピングルールで、事実上、日本語 EUC <-> Unicode 用のマッピングルールでしょう。 U005c, U007e での衝突を避けるために JISX0208 の 0x2140 ('\') が Uff3c (Fullwidth Reverse Solidus) に、 JISX0212 の 0x2237 ('・') が Uff5e (Fullwidth Tilde) にマップされます。それ以外に、JISX0221-JISX0201 と同様に JISX0208 の 0x213d ('―') が U2015 (Horizontal Bar) ではなくてU2014 (Em Dash) にマップされるのに加えて、 JISX0208 の 0x2131 (' ̄') が U203e (Overline) に、0x216f ('¥')が U00a5 (Yen Sign) にマップされる点が Unicode-1.1 と異なっています。

JISX0201 の代わりに ASCII を採用することで U00a5 と U203e が空きになるのですが、なぜわざわざそこを埋めなければならないのでしょう…? SJIS -> Unicode -> EUC あるいは EUC -> Unicode -> SJIS と変換した時のことを考えているのかと思ったんですが、例えば SJIS JISX0201 0x5c -> U00a5 -> EUC JISX0208 0x216f とすると半角円記号が全角円記号になっちゃいますし、あるいは SJIS JISX0208 0x216f -> Uffe5 -> EUC × とすると全角円記号がどこにもマップされないということになっちゃいますし…。

その後考えたのですが、Unicode がまずあってそれを既存の文字コードにマッピングする場合に U00a5 (Yen Sign) をマップする先がないというのが問題なのではないでしょうか。でも、そうだとしたら Uffe5 (Fullwidth Yen Sign) にもマップする先がないとまずいですよね…う~ん、そうすると今度は1対1対応でなくなっちゃうか。その辺はユーザの側で適宜対応してね、ということになるのでしょうか。

JISX0208 Unicode-1.1 JISX0221-ASCII
0x2131 (' ̄') Uffe3 (Fullwidth Macron) U203e (Overline)
0x213d ('―') U2015 (Horizontal Bar) U2014 (EM Dash)
0x2140 ('\') U005c (Reverse Solidus) Uff3c (Fullwidth Reverse Solidus)
0x216f ('¥') Uffe5 (Fullwidth Yen Sign) U00a5 (Yen Sign)
JISX0212 Unicode-1.1 JISX0221-ASCII
0x2237 ('・') U007e (Tilde) Uff5e (Fullwidth Tilde)


Windows における変換

従来の文字コードに ShiftJIS を使っているということで JISX0201 + JISX0208 ( + 外字) <-> Unicode というマッピングルールです。が、いろいろ変です。 JISX0201 の 0x5c が ASCII の 0x5c と明確に区別されることなくパス名の区切り記号として使われている & バイナリレベルでアプリケーションの互換性を保たなければならないために JISX0201 0x5c を U005c にマップするということをやっています。 JISX0208 の 0x2140 ('\') が Uff3c (FULLWIDTH REVERSE SOLIDUS) に、JISX0212 の 0x2237 ('・') が Uff5e (FULLWIDTH TILDE) にマップされるのはいいのですが、それ以外に、どういうわけか JISX0208 の '~', '∥', '-', '¢', '£', '¬' と JISX0212 の '・' が Unicode-1.1 と違うマッピングとなっています。 これらの文字が化けるという経験をしたことがある方は結構いるのではないでしょうか?

このあたりは XKP でも認識していて Microsoft に要望として出しているようですが、いまさら変更するようなことは恐らくしないでしょうねぇ。

JISX0201 Unicode-1.1 Windows
0x5c U00a5 (Yen Sign) U005c (Reverse Solidus)
0x7e U203e (Overline) U007e (Tilde)
JISX0208 Unicode-1.1 JISX0221-ASCII
0x2140 ('\') U005c (Reverse Solidus) Uff3c (Fullwidth Reverse Solidus)
0x2141 ('~') U301c (Wave Dash) Uff5e (Fullwidth Tilde)
0x2142 ('∥') U2016 (Double Vertical Line) U2225 (Parallel To)
0x215d ('-') U2212 (Minus Sign) Uff0d (Fullwidth Hyphenminus)
0x2171 ('¢') U00a2 (Cent Sign) Uffe0 (Fullwidth Cent Sign)
0x2172 ('£') U00a3 (Pound Sign) Uffe1 (Fullwidth Pound Sign)
0x224c ('¬') U00ac (Not Sign) Uffe2 (Fullwidth Not Sign)
JISX0212 Unicode-1.1 JISX0221-ASCII
0x2237 ('・') U007e (Tilde) Uff5e (Fullwidth Tilde)
0x2243 ('・') U00a6 (Broken Bar) Uffe4 (Fullwidth Broken Bar)


Sun の JDK における変換

Java では char 型が C/C++ のように 8bit ではなくて 16bit で Unicode を表します。ということでどういう変換を行っているか見てみると… EUC, JIS, SJIS ともサポートする必要があるためにか、これまた独自のマッピングルールを採用しています。
  • ASCII と JISX0201 Latin は同じ扱いとする。
  • U00a5, U203e が空きになるが、JISX0201 から変換された Unicode ではこれらが出てくることがあるので、Unicode -> ASCII の単方向のみそれぞれ 0x5c, 0x7e にマップする。と思ったら、U00a5 -> 0x5c はあるけど U203e -> 0x7e はないみたい。
  • JISX0208 0x2140 ('\') は ASCII との衝突を避けるために Uff5c にマップする。
  • JISX0212 0x2237 ('・') が U007e にマップされるが、未対応。 恐らく JISX0212 は誰も使ってないので誰も困ってなくて誰も Sun に報告してないのでそのままになっているんじゃないかと勝手に想像してます(^^;。

JISX0201 Unicode-1.1 Sun JDK
0x5c U00a5 (Yen Sign) U005c (Reverse Solidus)
0x5c <- U00a5 (Yen Sign)
0x7e U203e (Overline) U007e (Tilde)
0x7e <- U203e (Overline)
JISX0208 Unicode-1.1 JISX0221-ASCII
0x2140 ('\') U005c (Reverse Solidus) Uff3c (Fullwidth Reverse Solidus)

Bug Parade で JIS をキーに検索するといろいろ出てきますので興味のある方はどうぞ。 Windows で JISX0208 の '~', '∥', '-', '¢', '£', '¬' が化けることがあるという問題は Java のレベルで解決する類のものではない、としているようです。


mule-ucs における変換

mule-ucs-0.01.tar.gz について調べてみたところ、 Unicode-1.1 の規則をそのまま採用しているようです。

Be-OS における変換

伊藤隆幸さんが News に
From: yuki@dayo.ne.jp (ITO Takayuki)
Newsgroups: fj.os.beos
Subject: BeOS Unicode conversion survey
Date: 07 Mar 1999 18:33:07 GMT
Message-ID: <7bugqd$5af$2@horse.fsinet.or.jp>
という記事をポストされていますが、マッピングルールの問題、入力メソッドの問題、フォントの問題、文字幅の問題が重なっていろいろ苦労されているようです。

ここではその記事から分かる範囲でとりあえずマッピングルールについてのみ見てみます。 U005c が半角円記号に、U007e が Tilde に見えるということからすると、 ASCII と JISX0201 Latin を特に区別しているわけではなさそうです。 JISX0208 については、次の点が問題になっているようです。

  • 0x2140 ('\') が U005c (Reverse Solidus) にマップされているのは Unicode-1.1 と同じですが、Unicode -> JIS では U005c -> 0x005c となって元の 0x2140 に戻りません。
  • 0x2141 ('~') が U301c (Wave Dash) ではなく Uff5e (Fullwidth Tilde) にマップされます。
  • 0x215d ('-') が U2212 (Minus Sign) ではなく U002d (Hyphen-minus) にマップされていますが、Unicode -> JIS では U002d -> 0x002d となって元の 0x215d に戻りません。
  • 0x2160 ('÷') が U00f7 (Division Sign) にマップされているのは Unicode-1.1 と同じですが、Unicode -> JIS では U00f7 -> 0x00f7 となって元の 0x2160 に戻りません。
  • 0x217b ('○') が U25cb (White Circle) ではなく U25ef (Large Circle) にマップされます。


ベンダ定義文字の問題

NEC 特殊文字と IBM 拡張文字に関してですが、 JISX0208 と NEC 特殊文字の両方に入っている文字があったり、 NEC 特殊文字と IBM 拡張漢字の両方に入っている文字があったりします。これについては
XKP から入手できる WindowsNT 拡張漢字処理仕様書 2.1 の 5.1.2 重複符号文字の対応関係 のところにまとめてあるのでそちらをご覧頂くのがよろしいかと。

JIS エンコーディングの問題

ISO-2022-JP では ASCII, JISX0201 Latin, JISX0208 (ISO-2022-JP-2 ではそれに加えて JISX0212) が混在する可能性があるため、Unicode 上でこれら全てが区別できなければなりません。残念ながら上記のマッピングルールはいずれもこの条件を満たしていません。
  • Unicode-1.1 : 既に指摘したように ASCII と JISX0208, JISX0212 との混在ができません。
  • JISX0221-JISX0201 : ASCII を加えると U005c, U007e で衝突が発生します。
  • JISX0221-ASCII : JISX0201 を加えると U00a5, U203e で衝突が発生します。
  • Microsoft : ASCII と JISX0201 Latin を区別できません。また、Uff5e で衝突が発生しています。
  • Sun JDK : ASCII と JISX0201 Latin を区別できません。また、U007e で衝突が発生しています。
  • Be-OS : U002d, U005c で衝突が発生しています。
厳密には JISX0208-1978 と JISX0208-1983 も区別しなきゃいけないらしいですが、そこまでは調べていません。 そもそも、これらと Unicode の間のマッピングルールって存在するのでしょうか?

JIS エンコーディングにも対応した変換

Java と同じく EUC, JIS, SJIS ともサポートする方向で、 ASCII, JISX0201 Latin, JISX0208, JISX0212 と Unicode の間で1対1に対応が取れるように、と考えると以下のようなマッピングルールを採用するのが妥当かと思うのですがいかがでしょうか。


半角/全角の問題

工事中です。

その他の問題

工事中です。

Qt-2.0 のサポート状況

とりあえずメジャーどころとして
Unicode-1.1, JISX0221-JISX0201, JISX0221-ASCII, Windows, Sun それに JIS エンコーディングにも対応した変換 をサポートしています。 というか、サポートするようにしました:-)。 また、 Unicode とユーザ定義文字・ベンダ定義文字に関する問題点と解決策コード変換規則 に従う形で NEC 特殊文字, IBM 拡張漢字, ユーザ定義文字もサポートしています。

感想

内部文字コードとして Unicode を採用した場合について考えると…
  • I18N のための code set としては Unicode-1.1 は(多少 Know-How は必要だが)一応使える。
  • CJKV を含む M17N のための code set としては Unicode-1.1 は単独では使えない。 M17N に使おうと思ったら Unicode の文字列に何らかの形で言語情報等を付加する必要がある。
  • M17N ではなく I18N のために使うのであれば同時に一つの言語についてのみ考えればいいわけで、 CJK その他いろいろな言語が入り混じっていて巨大なテーブルを用意しないと変換できない Unicode を使わなくても、 16bit のところに JIS コードなら JIS コードをそのまま突っ込んでやってもいいんじゃないかな? ISO-8859-1 と重なるところだけ揃えてやれば実用上問題になることはあまりなさそうな気がしますが…。
  • Unicode-3.0(?) には言語タグ、異字体タグが入るそうで、そうなると CJKV を含む M17N にも使えるようになるのかな?

ソースコード


戻る

댓글 없음:

댓글 쓰기