English page もどる

変換表がベンダーによって異なる (2002-04-04)


はじめに

テキストファイルに実際に用いられる文字コードは、 「エンコーディング」と言います。 これは、例えば、EUC-JPShift_JISISO-2022-JPISO-8859-1UTF-8 などです。 エンコーディングは、ひとつまたは複数の「符号化文字集合」 (Coded Character Set, CCS) をその構成要素としています。EUC-JP というエンコーディングは、 ISO 646 IRV (ASCII と同じ)、JIS X 0208JIS X 0201 カナJIS X 0212 の符号化文字集合を構成要素としています。ISO-8859-1 というエンコーディングは、 ISO-8859-1 という符号化文字集合を構成要素としています。

さて、現在日本で広く使われているエンコーディングは、すべて、 JIS X 0208 などの符号化文字集合をその構成要素としています。 つまり、エンコーディングが異なっても、JIS X 0208 の文字であれば、同じ文字です。例えば、Shift_JIS における 0x82 0xA0 と、EUC-JP における 0xA4 0xA2 は、両方とも JIS X 0208 における 0x2422 で、厳密に同じ文字です。これは、ひらがなの「あ」で、 Unicode では U+3042 (あ) に変換するのが妥当です。

ところが、Unicode の登場以来、この平和な状況が脅やかされています。 日本で広く使われているエンコーディングや、 それを用いる実装において、同じ JIS X 0208 という符号化文字集合の 同じコードポイントを持つ文字 (つまり、同じ文字) が、 異なる Unicode コードポイントに変換される、 といったことが起こっているのです。

たとえば、CP932 (別名 Windows-31J) というのは、Microsoft Windows が用いている エンコーディングで、Shift_JIS に Microsoft 固有の文字 (「機種依存文字」と呼ばれることが多い) を追加したものです。 また、Macintosh も、Shift_JIS に Apple 固有の文字を追加した ものを使っています。つまり、Shift_JIS は、これらのエンコーディングの サブセットとなっています。これらのエンコーディングにおいて、 各社固有の拡張文字については、互換性がないのは当然ですが、 JIS X 0208 部分についても、一部の文字で互換性がなくなっています。 たとえば、Shift_JIS における 0x81 0x60 (JIS X 0208 の 0x2141) は、Macintosh や GNU libc を用いると U+301C (WAVE DASH, 〜) に変換されますが、CP932 における 同じ文字 (つまり、0x81 0x60 (JIS X 0208 の 0x2141)) は、 U+FF5E (FULLWIDTH TILDE, ~) に変換されます。 (Shift_JIS は CP932 のサブセットであるということに注意して ください。つまり、Shift_JIS を、CP932 であるとして扱っても 構わないのです)。

つまり、JIS X 0208 における厳密に同じ文字が、 Shift_JIS か、CP932 か、という解釈を変えただけで、 あるいは変換に用いるプラットホームに依存して、 別の Unicode 文字に変換されてしまうのです。 言いかえれば、あるテキストファイルを Unicode に変換すると、変換に用いるプラットホームに依存して、 それぞれ異なる Unicode ファイルになってしまいます。 今まで、JIS X 0208 を構成要素とする様々なエンコーディング間で、 ベンダ固有の拡張文字を除いた JIS X 0208 部分については データの完全な共有が可能であったにもかかわらず、 Unicode との変換表のせいで、一部の文字についてそれが不可能に なってしまったのです。

Unicode Consortium の立場としては、Shift_JIS、CP932、などなどの エンコーディングは全く別物であると解釈することで、 変換表が相違していても何ら問題はない、とするものです。 しかし、そのために、Windows や Macintosh で用いている文字は JIS X 0208 ではなく、したがって異なるベンダ間でのデータの 互換性は保証されない、ということになれば、その不利益は 大変なものになります。

また、変換表の不一致によって、 Unicode フォントは変換先のすべてのコードポイントに グリフを持つ必要が生じます。 mlterm が Unicode/JIS 変換テーブルとして CP932 を用いるオプションを 持っているのは、これに対処するのが目的です。 また、変換表の不一致 (と、もっと言えば、変換表には責任を持たない とする Unicode Consortium の立場) は、 文字幅問題 を複雑にさせるという問題もあります。 さらに、ファイルの同一性が問題となるような場面、 たとえば MD5 などのハッシュ値をとったり、diff コマンドを使ったりするような場面でも、このことは 問題になります。

ただし、Unicode から 日本のエンコーディング群 の変換においては、 多対一の変換を行うようにすることで、Shift_JIS のテキストファイルを Unicode に変換し、さらに Shift_JIS に変換すると、うまく元に戻ります。 (ただし、これは、同一の Unicode 文字が、別の変換表によって別の JIS 文字に変換されることがない、という前提が必要です)。


調査に用いたソフトウェア

日本の各エンコーディングと Unicode との変換について議論するには、 各エンコーディングと Unicode との変換表が必要になります。 ここでは、インターネット上で入手可能な、以下の変換表について 調査しました。これらの変換表が、実際に日本で広く普及している 変換ソフトウェアで用いられているかどうか、ということは 確認していませんが、おそらくそうだと思います。

これらのうち、

前回調査は、 JAVA の変換表も対象としていましたが、今回は省略しました。 これは、変換表が入手できていないからです。

調査に使ったスクリプトは、以下の通りです。

#!/usr/bin/perl

$JIS = 1;
$EUC = 2;
$SJIS = 3;

sub readmapfile ($$$$$) {
    my($file, $name, $legacy, $ucs, $type, $line, @column, $u, $l);
    ($file, $name, $legacy, $ucs, $type) = @_;

    print "reading $file ...\n";

    open(FILE, $file) || die "Cannot open $file.\n";
    while ($line = <FILE>) {
	if ($line =~ /^\#/) {next;}
	if ($line =~ m+^\/+) {next;}
	$line =~ s/^\s+//;
	@column = split(/\s+/, $line);
	if ($name eq "JISX0213") {
	    if ($line =~ /^2-/) {next;}
	    $u = $column[$ucs];  $u =~ s/u-/0x/;  $u = int($u);
	    $l = $column[$legacy];  $l =~ s/j-/0x/;  $l = int($l);
	} elsif ($name =~ /IBM1394/) {
	    $u = int("0x" . $column[$ucs]);
	    $l = int("0x" . $column[$legacy]);
	} elsif ($name =~ /GLIBC/) {
	    if ($line !~ /^<U/) {next;}
	    $u = $column[$ucs];  $u =~ s/<U/0x/;  $u = int($u);
	    $l = $column[$legacy];  $l =~ s+/x++g;  $l = int("0x" . $l);
	} else {
	    $u = int($column[$ucs]);
	    $l = int($column[$legacy]);
	}
	if ($type == $JIS) {
	    # do nothing
	} elsif ($type == $EUC) {
	    if ($l > 0x100) {$l -= 0x8080;}
	} else {
	    if ($l > 0x100) {
		$h = $l >> 8 & 0xff;
		$l = $l & 0xff;
		$out1 = ($h << 1) - ($h <= 0x9f ? 0xe0 : 0x160) 
		    - ($l < 0x9f ? 1 : 0);
		$out2 = $l - 0x1f - ($l >= 0x7f ? 1 : 0) 
		    - ($l >= 0x9f ? 0x5e : 0);
		$l = ($out1 << 8) + $out2;
	    }
	}
	${"map" . $name}[$l] = $u;
    }
}

# ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS0208.TXT
&readmapfile("JIS0208.TXT", "JISX0208", 1, 2, $JIS);

# ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/SHIFTJIS.TXT
&readmapfile("SHIFTJIS.TXT", "SHIFTJIS", 0, 1, $SJIS);

# ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP932.TXT
&readmapfile("CP932.TXT", "CP932", 0, 1, $SJIS);

# ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/APPLE/JAPANESE.TXT
&readmapfile("JAPANESE.TXT", "APPLE", 0, 1, $SJIS);

# http://www.jca.apc.org/~earthian/aozora/0213/jisx0213code.zip
&readmapfile("jisx0213code.txt", "JISX0213", 1, 4, $JIS);

# http://www.cse.cuhk.edu.hk/~irg/irg/N807_TablesX0123-UCS.zip
&readmapfile("IBM1394toUCS4-GLY.txt", "IBM1394", 0, 1, $SJIS);

# http://www.cse.cuhk.edu.hk/~irg/irg/N807_TablesX0123-UCS.zip
&readmapfile("IBM1394toUCS4-IRV.txt", "IBM1394I", 0, 1, $SJIS);

# GNU libc 2.2.5 from Debian libc6 2.2.5-4 package (2002-04-03)
&readmapfile("EUC-JP", "GLIBCEUC", 1, 0, $EUC);

# GNU libc 2.2.5 from Debian libc6 2.2.5-4 package (2002-04-03)
&readmapfile("SHIFT_JIS", "GLIBCSJIS", 1, 0, $SJIS);

print "JIS      0208   SJIS   CP932  APPLE  0213   IBMGLY IBMIRV G-EUC  G-SJIS\n";

for ($r = 0x0; $r <= 0x28; $r++) {
    if ($r > 0 && $r < 0x21) {next;}
    for ($c = 0x21; $c < 0x7f; $c++) {
	$l = ($r << 8) + $c;
	if ($l != 0x5c && $l != 0x7e && $l < 0x100) {next;}
	if ($l > 0x100 && $mapJISX0208[$l] == 0) {next;}
	if ($mapJISX0208[$l] != $mapSHIFTJIS[$l] ||
	    $mapJISX0208[$l] != $mapCP932[$l] ||
	    $mapJISX0208[$l] != $mapAPPLE[$l] ||
	    $mapJISX0208[$l] != $mapJISX0213[$l] ||
	    $mapJISX0208[$l] != $mapIBM1394[$l]) {
	    printf "0x%04X   ",$l;
	    foreach $i ("JISX0208", "SHIFTJIS", "CP932", "APPLE", "JISX0213",
			"IBM1394", "IBM1394I", "GLIBCEUC", "GLIBCSJIS") {
		if (${"map" . $i}[$l] == 0) {print "------ ";}
		else {printf "U+%04X ",${"map" . $i}[$l];}
	    }
	    print "\n";
	}
    }
}


調査結果

以下のようになりました。

JIS      0208   SJIS   CP932  APPLE  0213   IBMGLY IBMIRV G-EUC  G-SJIS
-----------------------------------------------------------------------
0x005C   ------ U+00A5 U+005C U+00A5 ------ U+00A5 U+005C U+005C U+00A5 
0x007E   ------ U+203E U+007E U+007E ------ U+203E U+007E U+007E U+203E 
0x2131   U+FFE3 U+FFE3 U+FFE3 U+FFE3 U+203E U+FFE3 U+FFE3 U+FFE3 U+FFE3 
0x213D   U+2015 U+2015 U+2015 U+2014 U+2014 U+2014 U+2014 U+2015 U+2015 
0x2140   U+005C U+005C U+FF3C U+FF3C U+FF3C U+FF3C U+FF3C U+FF3C U+FF3C 
0x2141   U+301C U+301C U+FF5E U+301C U+301C U+301C U+301C U+301C U+301C 
0x2142   U+2016 U+2016 U+2225 U+2016 U+2016 U+2016 U+2016 U+2016 U+2016 
0x215D   U+2212 U+2212 U+FF0D U+2212 U+2212 U+2212 U+2212 U+2212 U+2212 
0x216F   U+FFE5 U+FFE5 U+FFE5 U+FFE5 U+00A5 U+FFE5 U+FFE5 U+FFE5 U+FFE5 
0x2171   U+00A2 U+00A2 U+FFE0 U+00A2 U+00A2 U+FFE0 U+FFE0 U+00A2 U+00A2 
0x2172   U+00A3 U+00A3 U+FFE1 U+00A3 U+00A3 U+FFE1 U+FFE1 U+00A3 U+00A3 
0x224C   U+00AC U+00AC U+FFE2 U+00AC U+00AC U+FFE2 U+FFE2 U+00AC U+00AC 
なお、JIS の欄の 0x005C と 0x007E は、G-EUC と IBMIRV については ISO/IEC 646 IRV と解釈し、それ以外については JIS X 0201 ローマ字と 解釈するのが正しいです。

10 個の JIS X 0208 コードポイントについて、Unicode への変換が不統一です。


註釈

私の意見としては、どの変換表が望ましいか、望ましくないかは 二の次で、重要なことは、どんな形でもいいから統一することだと 思っています。しかし残念なことに、各ベンダは それぞれの過去の製品との互換性を保つ必要があり、 そのためには変換表の変更は認められないと思われるので、 これらの変換表ができて数年も経過した今となっては完全に手遅れで、 変換表の統一はもはや不可能だと思われます。 関係者の責任を厳しく追及したい気持ちです。

せめて、変換表の数をこれ以上増やさないことが必要です。 そのためには、公的で権威ある「正式」な変換表を、 ひとつ (または少数) だけ制定し、それをネット上で公開することが 必要だと考えます。

その他、今からでも「正式」な変換表をひとつ (または複数) 制定したほうがいい理由が、いくつかあります。

しかし、Unicode Consortium の見解は、Unicode Consortium は変換表については責任を負わない、というものです。 実際、Unicode Consortium は主に企業の集合体であり、 それらの企業たるや、不統一な変換表の現状を作りだした 帳本人ですので、そのような「正式」な変換表が決まれば 自分たちの変換表は間違った変換表ということになってしまい、 そんなことは企業のメンツをつぶしてしまうので、 Unicode Consortium にこの面でのリーダーシップを求めるのは 無理な話かもしれません。また、IRG の日本代表からも、 変換表は Unicode や ISO 10646 の側で定めるのではなく、変換先の 各々のエンコーディングの側で定めるのがよい、との 意見 があるようです。

それはそれでいいと思います。Unicode と JIS X 0208 との変換表の 最終的なよりどころは、JIS に求めるというのもよいでしょう。 ただし、JIS が責任を持てるのはただひとつの変換表だけであり、 広く使われている各ベンダの変換表については責任を持てません。 JIS の変換表や各ベンダの変換表など様々な立場を統合できる立場にある のは、様々な企業や団体が参加している Unicode Consortium をおいてほかにありません。

というわけで、以下のことを提案します。


そのほか

この問題については、Unicode Technical Committee にて議題にしてもらえるそうです。(2002-04-05)

今回は日本語エンコーディングのみを調査しましたが、 中国、台湾、韓国のエンコーディングも同様な問題を抱えているかもしれません。 特に、台湾で広く用いられている BIG5 はデファクトスタンダードですので、 大変な混乱が見られると聞きおよんでいます。


Tomohiro KUBOTA <debian at tmail dot plala dot or dot jp>