従来の文字コードとUnicodeの対応に関する諸問題

最終更新: 1998.12.20


目次

  1. はじめに
  2. 似た文字
  3. 旧JISと新JIS
  4. ベンダー固有文字
  5. 「全角」「半角」
  6. ASCIIとJIS X 0201ローマ文字
  7. おわりに
  8. 余談

1. はじめに

ISO/IEC 10646とUnicode(以下Unicode)は、いろいろと論議をかもしてきましたが、 すでにいろいろなところで陰に陽に使われるようになってきました。

Windows NTの内部コードがUnicodeであるのはよく知られています。 BeOSでは、内部だけでなく全面的にUnicodeが使われています。 また、Javaのchar型もUnicodeです。

しかし、とくに入出力においては、当分は従来の文字コードと共存することになります。 すなわち、意識するしないに関わらず、Unicodeと従来コードの変換が頻繁に行われます。 変換といっても、Unicodeコンソーシアムが提供しているテーブルを引くだけで、 何の問題もないように思いますが、 実は日本語環境だけに限ってもいろいろな問題があり、 特定の文字だけが正しく表示されないなどの現象を生むことになります。

本稿では、主に日本語環境に関係する範囲で、 従来JISとUnicodeとの対応づけあるいは変換に関する問題点について、 いくつか具体例を挙げて考察します。 Unicodeがらみの問題が起きたときの原因の推定や、 問題を引き起こさないような実装に役立ててください。

なお、本稿では、JIS X 0201、JIS X 0208、シフトJIS、 Unicodeなどについて基本的な知識があることを前提としています。 また、ISO/IEC 10646の規格書かThe Unicode Standard, Version 2.0 が手元にあるとなおよいでしょう。


2. 似た文字

Unicodeというと、その名前や、CJK統合漢字の件などから、 「似た形の文字を一つにまとめている」という点が(日本では)強調されているふしがありますが、 実際には、それは漢字だけの話といっても過言ではありません。 とくに記号類については、見た目がほとんど同じであっても、 役割や用途が違うものは積極的に別の文字として扱おうとしています。 また、ソース・セパレーションの原則(原規格で区別しているものは互換性のため区別する)も、 これに拍車をかけています。

例をあげると、ラテン文字のAとギリシア文字のΑとキリル文字のАはもちろん別の文字ですし、 ギリシア文字のμと百万分の一を意味するμも別の文字になっています。 また、ダッシュやハイフンなどの「横棒」系の記号はすさまじく、 以下のように細かく分かれています (ちなみに「空白」はもっとあります)。

U+002D HYPHEN-MINUS (ASCIIのマイナス)
U+00AD SOFT HYPHEN 語中の折り返し可能個所、表示されないかもしれない
U+2010 HYPHEN 複合語などの一般的なハイフン
U+2011 NON-BREAKING HYPHEN (右端でも折り返されないハイフン)
U+2012 FIGURE DASH (数字と同じ幅のダッシュ)
U+2013 EN DASH 数値の範囲、例:1973-1984
U+2014 EM DASH 語句を―このように―挿入するダッシュ
U+2015 HORIZONTAL BAR
(quotation dash)
引用などに使う
U+207B SUPERSCRIPT MINUS (上つきマイナス)
U+208B SUBSCRIPT MINUS (下つきマイナス)
U+2212 MINUS SIGN マイナス
U+301C WAVE DASH
U+3030 WAVY DASH 波線
U+30FC KATAKANA-HIRAGANA
PROLONGED SOUND MARK
仮名の長音
U+FF0D FULLWIDTH HYPHEN-MINUS (「全角」のマイナス)

ところで、上に挙げたたくさんのダッシュやハイフンを見て思うのですが、 こんなに細かく区別をして、はたしてどうやって入力するのでしょうか。 入力できたとしても、入力する人がちゃんと適切な記号を使い分けられるのでしょうか。 すでにJIS X 0208だけでも、仮名の長音とマイナスを混同したり、 引用符の左右をちゃんと使い分けていなかったりする例が後を絶たないというのに‥‥ まあ、そのうち、スペルチェッカーやスタイルチェッカーが教えてくれるようになるかもしれません。

さて、これだけ似た形の文字があると、 既存の文字集合との対応づけの際に、 人によって解釈が違ってくる可能性があることは否定できません。 もちろん、Unicodeコンソーシアムで対応表を配布してはいますが、 それは(漢字を除いて)あくまで参考にすぎませんし、改訂されることもあります。 また、各国の規格化団体が正式な対応表を作成したり、 各メーカーが変換テーブルを実装したりする際に、 さまざまなしがらみや思惑によって微妙な違いが生じることは十分考えられます。 そのため、どのような対応づけを採用するかによって、 コード変換の結果が一部異なったり、 特定の文字が表示されなかったりという事態が起こりえます。

JIS X 0208の中で、実際に問題になりそうなものを拾うと、以下のようなものがあります。

JIS X 0208Unicodeコメント
01-06 ・ 中点 U+00B7 MIDDLE DOT
U+2022 BULLET
U+2219 BULLET OPERATOR
U+22C5 DOT OPERATOR
U+30FB KATAKANA MIDDLE DOT
素直に考えればMIDDLE DOTですが、 日本の文字ですからKATAKANA MIDDLE DOTが 妥当なようにも思えます。
01-29 ― ダッシュ(全角) U+2012 FIGURE DASH
U+2013 EN DASH
U+2014 EM DASH
U+2015 HORIZONTAL BAR

01-30 ‐ ハイフン(四分) U+2010 HYPHEN
U+2012 FIGURE DASH
U+2013 EN DASH

01-33 〜 波ダッシュ U+223C TILDE OPERATOR
U+223E INVERTED LAZY S
U+301C WAVE DASH
U+FF5E FULLWIDTH TILDE
WAVE DASHが最適のはずなのですが、 印刷されているグリフが上下逆になっているのが気になります。
01-34 ‖ 双柱、平行 U+2016 DOUBLE VERTICAL LINE
U+2225 PARALLEL TO
単なる記号でしょうか、それとも数学的記号でしょうか?
01-35 | 縦線 U+007C VERTICAL LINE
U+2223 DIVIDES
U+FF5C FULLWIDTH VERTICAL LINE
FULLWIDTH VERTICAL LINEでしょうかね、やっぱり。
02-94 ◯ 合成用丸 U+20DD COMBINING ENCLOSING CIRCLE
U+25EF LARGE CIRCLE
名前からするとCOMBINING ENCLOSING CIRCLEですが、 この字は結局合成には使えないとJIS自ら認めてしまったので、 最近はLARGE CIRCLEとされています。

3. 旧JISと新JIS

旧JIS (JIS C 6226-1978)と新JIS (JIS X 0208-1983/1990/1997)の違いは厄介な問題ですが、ここでもまた顔を出します。

新JISはUnicodeの原規格の一つですので、 新JISとの対応づけは(少なくとも漢字については)明確に規定されています。 しかし、旧JISとの対応づけを考えると、やはり問題があります。

旧JIS漢字の一部は、新JISで字体変更や字体交換が行われました。 まず、字体交換が行われた文字について、 あくまで字体に忠実に対応づけをするか(つまり、新JISとは逆の対応づけをするか)、 それとも新旧JISを区別せずに新JISと同じ対応づけをするか、という問題があります。

また、字体変更が行われた文字について、 旧JISの字体がUnicodeに収録されていない場合、以下のような選択肢があります。

一方、旧JISの字体がUnicodeに収録されている場合 (JIS X 0212で救済されている場合や、たまたま他国の規格にあった場合)には、 以下のような選択肢があります。

ここで、選択肢があるというのは決してよいことではなく、 迷いの種が増えるだけであるということはいうまでもありません。


4. ベンダー固有文字

JIS C 6226-1978制定以前は、 各メーカーがそれぞれに日本語文字コードを策定していました。 JIS制定後も、それら独自コードとの互換性を維持したり、JISの不足分を補うために、 各メーカーはJISに独自の文字を追加した製品を提供しています。 いわゆる「機種依存文字」「ベンダー独自文字」などと呼ばれるものです。 ここでは、「ベンダー固有文字」と呼ぶことにします。

JIS C 6226に追加する形のベンダー固有文字集合としては、次の二つが有力です。

マイクロソフトがWindowsなどのフォントの文字集合として規定した 「マイクロソフト標準キャラクタセット」には、 JIS X 0208に加えて上記のベンダー固有文字が含まれています (ただし、NEC拡張文字の罫線や半角文字は除く)。 IBM拡張文字は、NEC拡張文字と重複していることになります。 また、これらベンダー固有文字は、 JIS C 6226-1978つまり旧JISの時代に策定されたものですので、 新JISで追加された文字や、JIS X 0212とも一部重複しています。

さて、これらとUnicodeとの対応を考えると、以下のような問題点があります。

たとえば、「昂」という字(JIS X 0208 25区23点)があります。 この字には、「昂A」という字体(U+663B)と、 「昂B」という字体(U+6602)があります。 旧JISでは、25区23点の字体は「昂A」でした。 そこで、異体字の「昂B」がIBM拡張文字(FAD0)に収録されました。 ところが、新JISでは25区23点は「昂B」に改められたので、 「昂B」が二つあって「昂A」がないという奇妙な事態になりました。 IBM拡張文字の方を、あくまで「昂B」として扱うか、 それとも新JISの字体交換に倣って「昂A」とみなすか、 いずれにしても混乱すること間違いなしです。

なお、IBM拡張文字の漢字のうち、 UnicodeのCJK統合漢字(CJK Unified Ideographs)でカバーされていないものは、 CJK Compatibility Ideographsに収容されています。


5. 「全角」「半角」

ASCII(またはJIS X 0201)とJIS X 0208を併用する場合に、 1バイトコードである前者を「半角」とし、 2バイトコードである後者を「全角」とする実装が広く存在しています。 そこでUnicodeでは、「半角カタカナ」と「全角カタカナ」、 あるいは「半角英数字」と「全角英数字」の区別を保存できるようにするため、 通常の英数字やカタカナとは別に、 Halfwidth and Fullwidth Formsという互換文字領域を設けて、 「半角カタカナ」と「全角英数字」を収容しました。

しかしながら、 Halfwidth and Fullwidth FormsFULLWIDTH文字をよく見てみると、 はたしてどれに対応するのかが不明な文字がいくつかあります。

U+FFE0 ¢ FULLWIDTH CENT SIGN
U+FFE1 £ FULLWIDTH POUND SIGN
U+FFE2 ¬ FULLWIDTH NOT SIGN
U+FFE4  FULLWIDTH BROKEN BAR

これらは、ASCIIやJIS X 0201にはありませんので、 わざわざ「全角」を別途用意する必要はないはずです。 何に使うのでしょうか。

最初の3つは、おそらくコードページ942/943との変換に使うためのものと思われます。 DOSやWindowsでは、シフトJISのことをコードページ932と呼びますが、 IBMがこれを拡張したコードページ942/943というものがあります。 これは、以下のように、シフトJISで使わないコードに1バイト文字を割り当てたものです。 これらはすべてJIS X 0208にもある文字ですので、 その区別を保存するには、X 0208の方と対応するFULLWIDTH文字が必要となります。

80	U+00A2 ¢ CENT SIGN
A0	U+00A3 £ POUND SIGN
FD	U+00AC ¬ NOT SIGN
FE	U+005C \ REVERSE SOLIDUS
FF	U+007E 〜 TILDE

ところで、Halfwidth and Fullwidth Formsがあるから「半角」「全角」の区別が容易に保たれる、と考えるのは早計です。 Halfwidth and Fullwidth Formsは、 (たとえば)JIS X 0201とJIS X 0208の間で重複している文字を区別できるだけであり、 それ以外の文字(JIS X 0208の大部分)をUnicodeに変換した場合は、 それが「全角」であるという属性は失われることに注意が必要です。

例として、ktermのような等幅フォントの端末エミュレータをJavaで作ったとしましょう(別にJavaでなくてもいいですが)。 この場合、JIS X 0208の英数字は、Halfwidth and Fullwidth Formsにマップされますので、「全角」であることがわかりますから、 これを表示するのに全角フォントを使うことは可能です。 また、仮名や漢字は当然全角フォントになるでしょう。 しかし、それ以外の非漢字、特に記号やギリシア文字・キリル文字などは、 Unicodeにマップした時点で「全角」「JIS X 0208由来」という属性は失われてしまい、 ISO 8859などと一緒の(おそらくは半角の)フォントで表示されることになるでしょう。 あるいは、強いてそれらを全角で表示することもできますが、 その場合はISO 8859などからきた文字も全角で表示されてしまいます。 もちろん、元の属性を保存するような実装を講じればいいのですが、 いずれにしても、素のUnicodeだけではどうにもならない問題です。

Unicode Consortiumは、このような問題に対処するために、 各文字にEast Asian Widthという属性(informative property)を定義することにしました。 しかしこれでも曖昧さがなくなったわけではなく、 またここで参考として挙げられている分類はいささか疑問なものもあります。


6. ASCIIとJIS X 0201ローマ文字

日本で使われている1バイト英数字の規格としては、ASCIIとJIS X 0201ローマ文字があります。 両者の違いは05/12と07/14の2か所だけです。 しかし、これらとJIS X 0208を併用した文書をUnicodeに変換しようとすると、 わずか2か所の違いが、他の文字の対応づけに少なからぬ影響を与えます。

まず、ASCIIとJIS X 0208(とJIS X 0212)を併用した場合について考えてみます。

これをまとめると、下表のようになります (注意すべきところは強調表示にしてあります)。

既存の文字集合 Unicode
ASCII 05/12 \ REVERSE SOLIDUS U+005C \ REVERSE SOLIDUS
07/14 〜 TILDE U+007E 〜 TILDE
JIS X 0208 01-32 \ バックスラッシュ U+FF3C \ FULLWIDTH REVERSE SOLIDUS
01-79 ¥ 円記号 U+00A5 ¥ YEN SIGN
01-17  ̄ オーバーライン U+203E  ̄ OVERLINE
JIS X 0212 02-20  ̄ マクロン U+00AF  ̄ MACRON
02-23 〜 チルダ U+FF5E 〜 FULLWIDTH TILDE

次に、JIS X 0201とJIS X 0208(とJIS X 0212)を併用した場合について考えてみます。

これを上の表に書き加えると、下のようになります。

既存の文字集合 Unicode
ASCII使用時JIS X 0201使用時
ASCII 05/12 \ REVERSE SOLIDUS U+005C \ REVERSE SOLIDUS
07/14 〜 TILDE U+007E 〜 TILDE
JIS X 0201 05/12 ¥ 円記号
U+00A5 ¥ YEN SIGN
07/14  ̄ オーバーライン U+203E  ̄ OVERLINE
JIS X 0208 01-32 \ バックスラッシュ U+FF3C \ FULLWIDTH REVERSE SOLIDUS U+005C \ REVERSE SOLIDUS
01-79 ¥ 円記号 U+00A5 ¥ YEN SIGN U+FFE5 ¥ FULLWIDTH YEN SIGN
01-17  ̄ オーバーライン U+203E  ̄ OVERLINE U+FFE3  ̄ FULLWIDTH MACRON (???)
JIS X 0212 02-20  ̄ マクロン U+00AF  ̄ MACRON U+00AF  ̄ MACRON
02-23 〜 チルダ U+FF5E 〜 FULLWIDTH TILDE U+007E 〜 TILDE

このように、ASCIIをとるかJIS X 0201をとるかによって、 JIS X 0208およびX 0212の関連する文字の対応づけが大きく変わってしまうことがわかると思います。

もっとも、ここまで厳密に対応づけを調整しても、実際はあまりメリットはありません。 むしろデメリットのほうが大きいでしょう (元がASCIIかJIS X 0201かわかっていない限り可逆変換が保証できないとか、 2バイト文字がFULLWIDTHになったりならなかったりするなど)。

そこで、現実には、JIS X 0208やX 0212はなるべくFULLWIDTHに追いやってしまい、 どちらの場合にも適用可能な単一の対応づけによって運用することになるでしょう。 そのような対応づけの一例を下表に示します。

既存の文字集合 Unicode
ASCII 05/12 \ REVERSE SOLIDUS U+005C \ REVERSE SOLIDUS
07/14 〜 TILDE U+007E 〜 TILDE
JIS X 0201 05/12 ¥ 円記号 U+00A5 ¥ YEN SIGN
07/14  ̄ オーバーライン U+203E  ̄ OVERLINE
JIS X 0208 01-32 \ バックスラッシュ U+FF3C \ FULLWIDTH REVERSE SOLIDUS
01-79 ¥ 円記号 U+FFE5 ¥ FULLWIDTH YEN SIGN
01-17  ̄ オーバーライン U+FFE3  ̄ FULLWIDTH MACRON (???)
JIS X 0212 02-20  ̄ マクロン U+00AF  ̄ MACRON または
U+FFE3  ̄ FULLWIDTH MACRON
02-23 〜 チルダ U+FF5E 〜 FULLWIDTH TILDE

こうすると、たしかに対応はすっきりするのですが、 互換領域であって本来使うべきでないはずの FULLWIDTHを多用することになるという問題が残ります。 たとえば‥‥

円記号を記述する際に、JIS X 0201の円記号を使うと、 環境によってはASCIIのバックスラッシュで表示されてしまうおそれがあるため、 筆者はなるべくJIS X 0208の円記号を使うことにしています。 これを、上記の対応づけによってUnicodeに変換すると、 正規形として使っていたはずのX 0208の円記号が、 ことごとく互換文字のFULLWIDTH YEN SIGNにマップされてしまいます。 しかも、Unicodeでの円記号の正規形であるYEN SIGNはまったく使われないのです。 このように、文字コードに気を配って記述していたはずのものが、 変換されるとまったくおかしなものになってしまいます。

円記号については、他にも問題となるケースが考えられます。 JIS X 0201の円記号は、文字通り円記号を表現するために使われる場合もあれば、 ASCIIのバックスラッシュの代わりに05/12というコードを表現するために使われる場合もあります。 Cのソースコードなどは後者の例です。 JIS X 0201をUnicodeに変換する場合、 後者の円記号をU+00A5 YEN SIGNに変換するわけにはいきません。

以下のソースコードは、両者の用法が混在しています。 このようなものは、単純にコードコンバーターにかけるだけでは済みません。

printf ("合計金額 \\%d\n", total);

7. おわりに

本稿のネタのいくつかは、「ISO 10646のJIS化に関する説明会」の場で、 従来JISとの相互運用にまつわる問題点として担当者の方から解説があったものです。 よく目につく問題を含んでいるにもかかわらず、 一般にはほとんど認識されていないようなので、 そのときのメモを整理・補足して広く情報提供しようと思ったのが、 本稿を書いた一番の動機です。

Unicodeの問題点というと、漢字統合が真っ先にとりあげられます。 もちろんこれも問題なのですが、 大多数のアプリケーションユーザーにはCJK混在など縁のない話であり、 漢字統合の問題が意識される機会はそれほど多くないことと思います。 むしろ、これから増えるであろうUnicodeベースのシステムにおいて、 一般ユーザーが直面する問題の多くは、 本稿でとりあげたような雑多な問題でしょう。


8. 余談

CJKの非Unicodeなコード系に目を転じると、 最近はシフトJIS的な符号空間を使って文字数を増やすのがはやりのようです。

中国ではGBKといって、従来の標準である中国語EUCの周辺にUnicodeの漢字を押し込んでいますし、 韓国では統合ハングルコード(UHC)といって、同様に韓国語EUCの周辺にハングルの不足分を押し込んでいます。 本家(?)日本でも、シフトJISがJIS X 0208-1997に盛り込まれただけでなく、 シフトJISの隙間に埋め込むことを想定した JIS第3・第4水準と称する文字集合の策定が行われようとしています。 聞くところによると、香港ではBig5をさらに増やそうという動きすらあるとか。 CJKの協調やISO 2022などどこへやら、 自国の要求を満たすためにはなりふりかまわぬといった感じです。


Copyright (C) 1998 ITO Takayuki, All rights reserved.

伊藤隆幸のホームページ