JAVA PRESS Vol.15
『当世JAVA日本語事情』
-JAVAで日本語を扱う際の問題点-
入校バージョン

伊賀みどり (http://www003.upp.so-net.ne.jp/midori/midosoft.html)

  • タイトル : JAVA PRESS Vol.15 入校原稿 : 『当世JAVA日本語事情』
  • 説明 : 『当世JAVA日本語事情』 -JAVAで日本語を扱う際の問題点- : 入校原稿そのまま
  • キーワード: Java,日本語,文字化け,文字コード,エンコード,エンコーディング

JAVA PRESSサポートページへ戻る

前提
はじめに

ここ最近、JAVAが猛烈な勢いで流行していると感じられます。特にサーバ側のプログラミングに着眼すると、新規案件のサーバサイドはJAVAでプログラミングするというのが、既に業界常識として定着してきたように思えます。
他方、XML関連技術の採用についても世間では徐々に立ち上がりつつあるようでして、これもまたJAVAの流行を助長しているようです。
JAVA言語はもはや、果敢な開拓精神のもとキモダメシ的に取り組むというフェーズを完全に終焉させてしまい、むしろ一般システム構築の際に最初に検討されるべきデファクト言語という新たなフェーズにさしかかってきたようです。

このように怒濤の如くJAVA言語が流行すると、それに見合っただけ多くの問題が顕在化してしまいます。それら問題の中でも特に目立って多いのが日本語関連処理に関わる問題であるように私は思っています。(だからこそ、この記事を執筆していますし、それが理由で この記事を読まれているという読者の方々も多いことでしょう :-)
日本語関連問題の原因の幾つかは、JAVA実行環境そのもの実装上の不具合・日本語対応の不完全さやJAVAで実装されたパッケージソフトウェアの日本語対応の不完全さに起因することもあるのですが、実はそれよりもむしろ利用者の文字コード関連情報に対する情報・認識の無さこそが原因であるケースの方が最近は多いようです。

本稿ではJAVA日本語関連処理にまつわる問題について、文字コードに関わる情報を中心に扱ってまいります。事前に知っておきたいJAVA関連文字コード情報やJDKバグ情報、問題が発生してしまった際の原因究明方法・対処方法などを扱っていきます。
なお予め断っておきますが、私は文字コードの研究家や専門家ではありません。専門家に比べて誤りを書いてしまう可能性も多いものと思われます。(目安を出しておきますが、ご存じかも知れませんが、私はJDBC-ODBC Bridgeをスクラッチで書くなどの経験や技術は持ち併せております :-)
しかし専門家で無いからこそ一般の方々に伝わりやすい日本語関連情報を書けるのでは無いかと思っております。

背景

ちょっと昔(ほんの5-6年前ころまで)、文字コードに関する一般的な書籍は入手しにくかったように覚えています。むろん専門家や研究者の間で、または汎用機メーカーの関連エンジニアなどの専門家の間では資料などはあったのも確かです。この時代は文字コードにとって、いわば暗黒時代でした。コード変換は 何やら怪しげな黒魔術のように思われていました。
しかし一方 文字コードに関する知識・技術に関しては マルチプラットホームに関わる人にとってはどうしても必須の能力でして、従事者の方々は さまざまな努力・苦労をしながら習得していったものです。

そんな中、一般向けの書籍として
・日本語情報処理
著者: Ken Lunde(小林剣)
訳者: 春遍雀來(ハルペンジャック)、鈴木武生
発行所: ソフトバンク株式会社 出版事業部
ISBN4-89052-708-7
が出版されました。(参考文献*1)

この本が当時としては画期的な内容だったです。それどころか現在においても日本語情報処理に関するバイブルとして定番中の定番として君臨しています。この本は文字コード初心者向けの入門書ですが、中級者がリファレンスとして利用するに耐えうる高い品質を兼ね備えています。
この記事の第1の成果は、この本の存在を読者に紹介することです。文字コードで困っているのにこの本を所有していない方へ、この本を強くお薦めします。

『日本語情報処理』登場以降 何年か経過している間に、いまどきの日本語処理事情という観点からは 『日本語情報処理』の内容はさすがに陳腐化して来ました。
そんな中 "最新の" 日本語処理事情に対応した 純国産の日本語処理書籍が登場したのです。

何かしら日本語情報処理に携わる日本人エンジニアにとって、この本の存在はかなり貴重です。というのも この本には最近の日本語処理関連情報に対応しているのみならず、外字・シフトJIS・Unicode・Mimeなどの具体的な実装・その問題点・背景・経緯・果ては具体的なプログラミングに至るまで 、エンジニアとしての立場・切り口から極めて明快に論ぜられているからです。他方 日本語文字コード関連JISの概観・歩き方という用途でも便利に利用できます。なぜなら 各JISに関する説明はもちろんのこと、各々へのコメントや所見まで載っているからです。
この本では、本稿が後述するようなJAVA関連の文字コード問題が 既に予見・指摘されています。それら問題の背景や その本質を知るために この本の通読を強くお薦めします。

一方 JAVA言語に特化した範囲における文字コード関連書籍は、ごく先日まで存在しませんでした。しかし喜んでください。つい最近、次の書籍が出版されたのです。
・Javaプログラミング・ノート -国際化と日本語処理-
著者: 風間一洋
発行所: 株式会社アスキー
ISBN4-7561-3481-5
(参考文献*2)

コラム
著者の風間一洋さんは 書籍以外にも ウェブ上に 文字コードに関する資料の一部を掲載されています。この本の内容の一部を垣間見ることができます。

この記事の第2の成果は、この本の紹介です。JAVA言語で且つ文字コードで困っているのにこの本を持っていない方はすぐ入手すべきです。この本は文字コードやUnicodeに関して貴重な情報を提供しています。例えば エンコーディング名のリファレンスとしてだけでも入手の価値があります。(私は主にそれを用途としています :-) というのも、現在エンコーディング名一覧としてだけでも、この本以外からは情報が入手困難な状況なのです。

これら書籍の出版によって、JAVA言語における文字コード関連書籍の定番が出そろったのです。もはやJAVA言語の文字コード情報に関しては暗黒時代を終えているのです。
そのようなことで、本稿は予め上記書籍について最低でも1回は読んでいることを想定して書いてあります。『そもそも文字コードなんて意識すらしたくない』という方も多いことでしょう。確かに 従来既存言語では文字コードに関して、同一メーカーの同一OS間でのデーター相互交換の範囲だと意識することが少なかったから特にそのように思われることと思います。
しかしJAVA言語においては、文字コード関連でひとたび問題が発生してしまうと避けて通れなくなってしまう傾向があります。しかもその仕組みの理解を怠って場当たり的な対処でやり過ごそうとしても、どんどん問題が複雑化してひどいことになるケースが多いようです。(例えば "ISO8859_1" は悪魔の呪文的に使われがちですよね :-)
特に 実際に文字コードの問題に遭遇してしまった方々は、ここは腹をくくって まずは上記3冊の書籍に目を通すべきであると強くお薦めいたします。

<脚注 コメント=脚注またはコラムにて挿入希望>
それら以外に どうしても挙げておくべき資料があります。
・JIS X 0208:1997 「7ビット及び8ビットの2バイト情報交換用符号化漢字集合」,日本規格協会
財団法人 日本規格協会 http://www.jsa.or.jp/
残念なことに 筆者は この資料に目を通した事がありません。また 個人で購入するには高価であることも
所有していない大きな理由です。ただし 『公式な』JISに関する資料でありますので、文字コードに関わる話や
JISのリファレンスとして 引用されることが多いです。
(参考文献*3)
</脚注>

私がほぼ1年前に執筆した JAVA PRESS Vol.8 p.11〜 『Javaデータベース技法と日本語事情』-日本語処理上の問題とその解決策- についても もし入手可能でしたら併せてお読みいただければ幸いです。(参考文献*4)
思えば あの頃からは ずいぶん状況が改善されたり変化したりしています。また Vol.8で行ってしまった間違いの記載についても、この場を借りて修正します。

これらの資料を概観してみると、プログラミング言語以前の話題として下記のような数点の問題提起を主に見いだすことが出来ます。

最近は こういった話題は メールやウェブページにおける『使える文字』といったくくりの中で扱われたりすることがあります。この問題の根底には ここ最近の Windows98/95のクライアントOSとしての圧倒的市場シェアが関連していると言われています。
一方 これらの問題に対する根本的な解決方法は 昔も現在も相変わらず存在していません。(それゆえ未だに問題として残存しているのでしょう) むしろUnicodeの出現がそれら問題を よりくっきりと浮かび上がらせているようにすら思えます(苦笑)

瞬間速習 文字コード問題

この記事の中でも ほんの少しだけ文字コードについて説明いたします。ごくごく基本的で初歩的な事柄のみを記載いたします。初級的レベル以上の内容は 前述の本を見ていただきたく思っております。

ごく身近な話から入りましょう。私たちがコンピュータと向き合って作業をしている際には 文字がグラフィカルイメージとして表示されます。例えば 『愛』という文字は コンピュータの画面上や印字上では このように表示されることでしょう。

ところが オフィスソフトなどの殆どのソフトウェアでは このデータをイメージデータとしては持っていません。文字コードという1バイトから2バイトで1文字を表現する形態で内部的には保持しているのです。Microsoft Windows98 などで用いられている文字コード体系 『シフトJIS』 で考えると、『愛』 という文字は 16進表記で 88 a4 という 2バイトの文字コードになります。(以降 特に断らない限り 文字コードは16進表記で記載します) このコードを 特定のフォントを通過させることにより 『愛』 という最終的なイメージデータを得ることが出来るのです。(もちろん特定用途のソフトウェアでは 文字コードとして保存せずに イメージデータやベクトルデータなどの形態で保持していますね :-)

ところが 日本国内に限って見ただけでも 文字コード体系は これ以外に 多数存在します。多くの場合 オペレーティングシステムの種類が異なると 文字コードは異なってしまいます。そして 別の文字コード体系環境下では 同じ『愛』 の文字が 例えば b0 a6 であったり (0e) 45 c6 (0f) であったりするのです。そうすると 日本国内に限っただけであっても データの相互交換は 頭の痛い内容になってきてしまいます。

さらに世界に目を広げると もっともっと問題が広がります。同じ種類のオペレーティングシステムであったとしても、違う国/言語バージョンであった際には シフトJISで利用している 88 a4 には 別の文字が割り当てられて利用されている可能性があるのです。(実際そうでしょう)

ところが インターネットの異常な発展/流行により 同じウェブページが様々な国/言語の利用者からアクセスされるようになってきましたし、逆に同じコンピュータから多種多様な言語で書かれたページにもアクセスするでしょう。そうすると 同じ文字コードで複数の文字イメージが割り当てられている現状はとても困ります。
このような背景から 最近では Unicodeと呼ばれる 新しい文字コード体系が利用されるようになってきています。Unicodeを用いれば 『愛』 という文字は 61 1b と表現されますが、Unicodeにおいては 61 1b は どのような国/地域であっても 必ず 『愛』 という文字を表現するように設計・実装されています。Unicodeは そのような 多国籍多言語環境に最適な文字コード体系であると考えられます。そして JAVA言語はもちろん 内部的な文字コードとして Unicodeを採用しています。他に有名な例えとして、 Windows2000/NT4.0やVisualBasicも 内部的な文字コードはUnicodeを採用しています。

ピンポイントコラム
現状 日本国内での漢字の表現方法は 多くの場合 2バイトで表現されています。これは 現在シェアの多くを占めているオペレーティングシステムがそのような実装である事も大きな理由ですが、それと同じくらい大きな問題として 2バイトを超えるバイト数の文字コードは既存の言語処理系のプログラム記述の中での扱いにくさも大きいと感じています。やんごとなき事情により 現状の文字コード(私の経験ではシフトJIS)に 無理矢理 3〜4バイト文字コードの概念を採用して文字コードの不足を解消するような特殊ケースすら存在します。(人名処理などで どうしても文字コードの不足が発生してしまう場合があるのです)。このプログラミングは かなり苦痛だったです (笑)
一方 文字コードのサンプルとして例に挙げた (0e) 45 c6 (0f) のカッコ内の文字は 漢字IN と 漢字OUTと呼ばれるコードになります。これは 表示するための文字では無く、ここから漢字が開始され ここまでが漢字であるのだということを表現するための 機能コードに該当します。このような機能コードもオペレーティングシステムの種類によって異なります。
ただし 例えばシフトJISでは 漢字IN , 漢字OUTは利用されません。その代わりに 1バイト目がある値の範囲の値に入っているかどうかによって 漢字コードか 1バイト文字かを判定しているのです。この判定方法がくせ者でして、結果的にプログラミングを難しくしています。また この難しさは 欧米で動作するソフトウェアを日本語化する際の 最大の難関でもあります。
ところが、 Unicodeは違います。Unicodeを用いれば 漢字IN/OUTは不要な上に 1バイト目の最上位ビット判定も不要なのです。このおかげで Unicodeベースのソフトウェアは 日本語化(国際化や地域化)が実装しやすいのです。Unicodeって 夢の文字コード体系なのです。もちろん JAVAはUnicodeを採用しています。なお このコラムでは Unicodeを UTF-16 であるのだとして説明を加えました。本来は UTF-8やISO-2022-JP等についても言及すべきでしょうが、それら詳細に関しては 参考文献2を参照下さい

JavaVMは 内部文字コード体系としてUnicodeを採用することにより、同一バイナリで多国籍多言語に対応しています。(もちろん 文字コード以外にも多くの努力が費やされている事でしょう :-) Windows版 Java2 SDK 1.3 国際版などそのものがそうですよね。私たちは 無意識のうちに Windows版 Java2 SDK 1.3 国際版を日本語版が如く利用していますが、実は あの同一バイナリそのものが 別の国や地域で そのまま動作しているのです!

Unicodeを内部文字コードとして利用していると、Unicodeとプラットホーム文字コードとの間の変換が必要になってきます。JAVA言語においては、デフォルトでの文字コード変換を持っているのはもちろんのこと、明示的な文字コード変換の機能も 言語仕様として明確に持ち合わせています。
ちょっとしたファイル入出力のサンプル Test2.java をベースに説明していきますと、ソースコード上の "愛" はもちろん Unocodeでして、61 1b と表現されています。次に "愛".getBytes("MS932") と記載することにより その値は 88 a4 に変換されます。このため このサンプルでは ファイルに書き込まれる値は 『シフトJIS』な 『愛』 (88 a4) という文字であることになります。逆に ファイルから読み込んだ値を new String(byteRead,0,iLength,"MS932") しますと、ファイルから読み込まれた シフトJISな表現である 88 a4 が Unocodeな 61 1b に変換されています。(より正確な表現をするとくどくなりますが、、、その読み込み後文字データは System.out.println(strWrk) のタイミングで さらに 61 1b88 a4 に変換されてコンソール画面に出力されているのです)
ここで "MS932" というキーワードは、丁度 Windows版 Java2 SDK 1.2以降の デフォルトのエンコーディングを表す文字列です。(後述しますが 1.1.7以前では "SJIS" がデフォルトのエンコーディングです。私は JAVA PRESS Vol.8 を書いた頃 この点を誤解しておりまして、Java2 SDK 1.2 においても "SJIS"がデフォルトエンコーディングであるという誤った認識および記載をしてしまいました。すみませんでした。) そのため Windows環境下で Java2 SDK 1.2以降を利用している場合には "愛".getBytes() や new String(byteRead,0,iLength) のように エンコーディング指定の引数を省略しても 暗黙の内に "MS932" として処理され、同等の結果を得ることが出来ます。
これを クドいと見るか 画期的と見るかなのですが、私は 大変に画期的な事なのだと考えています。というのも この仕組みのおかげで 同一バイナリなロードモジュールが 複数のオペレーティングシステム環境や複数の言語環境で動作することを実現しているからです。

そのような 夢の文字コード体系 『Unicode』 と それを採用した夢の言語処理系JAVA言語ですが、問題が全く無いわけではありません。JavaVM自身の実装上の不具合(バグ) というケースもありますし、Unicodeベンダー同士の見解の相違という困った問題もあります。(これらは後述しています)
それ以前に 利用者の Unicodeに対する無理解や JavaともUnicodeとも無関係な インターネット関連技術それ自身に対する無理解もあります。
これらが複合的に作用して JAVA言語関連の日本語処理は難しいという印象を受けてしまっているように思えます。

良く 『文字化けしてしまった』 という表現がありますが、この文字化けにも様々なタイプがあります。

  1. 別の文字コード体系の文字を無理矢理画面表示しようとして 全く無関係なフォントイメージが表示されて 無意味な表現がなされる
  2. JavaVMの文字コード変換ルーチンが 該当する変換後の文字が存在しないので 仕方なく "?" を出力するケース
  3. そもそも文字コード指定などに本質的な誤りがあり "?" が出力される。全ての文字が "?" なら諦めがつくのに 英数字だけは正常に表現されるからたちが悪い (笑)
  4. インターネット関連の場合に インターネットでは 7bitデータしか許容しない (最上位ビットは0でないと正常に動作しない) ケースを考慮して、ウェブブラウザなどのインターネット関連ソフトが (無意識のうちに) 勝手にコード変換を行ってしまい、結果的に サーバ側ソフトに到達したデータは (意味がわからないと) 文字化けしたように見えてしまう。
  5. ほんとうに JavaVMがバグっていて ごく一部の文字が "?" になってしまったり、その文字が欠落した上に以降の文字が欠損してしまう

最近の動向を見ていると 実際のほとんどのケースにおいては 利用者の間違いが原因で文字化けしている場合が多いように見受けられます。
しかしそれでも バグな事象も確かに存在しますので、それを切り分けして行かなくてはなりませんね。

文字コード問題のプライマリケア

運悪く文字コード問題に遭遇してしまった場合には、最初にその原因や発生箇所を追求すべきです。文字コード問題が深刻化しやすいのは、『見えるのに見えない』という やや哲学的なその本質にあります。『何だか分からないが さしあたり場当たり的に対処できればいいや』的スタンスで扱うと、多くの場合問題がひどくこじれがちです。
幸い プログラミング言語を扱っている際に文字コード問題に遭遇した場合には、私たちにはデバッグトレースを撃ち込むという ごく一般的な対処方法があります。最近は JDKの全ソースコードやXMLパーサーのソースコードは入手できることが多いので、従来は不可能だった そのようなライブラリの箇所についても デバッグトレースを撃ち込むことができます。(すばらしい世の中になったものですね)

<脚注>
JDKのソースコードについて、若干言及しておきます。JDKのソースコードには JDKに標準添付される その部分的なソースコードと SUNのウェブサイトから別途ダウンロード可能な JDKの完全なソースコードとの2種類が存在します。ここで筆者が指しているのは SUNのウェブサイトから得られた完全なソースコードを意味します。サイズが巨大ですので、潤沢なネットワーク環境が無いと なかなかダウンロードしずらい現状があることも確かです。一般公衆アナログ回線だと少し辛いでしょう。ISDNで64Kデジタルでダウンロードできるのでしたら、それほど難しいファイルサイズでは無いように私は考えています。むろん SUNと直接契約しているライセンシーの方(または会社) では それとは別の経路にてソースコードを扱っておられるようです。
普段からの心がけとして、ソースコードを入手して それを読む習慣を私はお薦めします。ソースコードを入手できずにブラックボックスとして扱うのとソースコードを見ながらとの間には 生産性に大きな開きが出るからなのです。
</脚注>

残念ながら ある特定箇所についてソースコードが入手不能であるのだとしたら、そのブラックボックスな箇所に入る直前などに、デバッグトレースを挿入するのが有効であることが多いです。
それでは、ごく単純なデバッグトレースコードをソースコードで示します。
MdDump.java (添付のソースコードを展開)
なお、この結果は WindowsNT2000 + SUN Java2 SDK 1.3 での結果になります。(以降 この環境をデフォルトとします)

Unicodeの文字コードダンプ
MdDump.dumpString("ABCDExyzあいうえお柿区 本日は晴天なり")
00 41 00 42 00 43 00 44 00 45 00 78 00 79 00 7a
30 42 30 44 30 46 30 48 30 4a 67 ff 53 3a 30 00
67 2c 65 e5 30 6f 66 74 59 29 30 6a 30 8a

MS932コードページでバイト化後、文字コードダンプ
MdDump.dumpBytes("ABCDExyzあいうえお柿区 本日は晴天なり".getBytes("MS932"))
41 42 43 44 45 78 79 7a 82 a0 82 a2 82 a4 82 a6
82 a8 8a 60 8b e6 81 40 96 7b 93 fa 82 cd 90 b0
93 56 82 c8 82 e8

古典的ダンプ表示手法による Unicodeの文字コードダンプ
0: A B C D E x y z
00 41 00 42 00 43 00 44 00 45 00 78 00 79 00 7a
8: あ い う え お 柿 区  
30 42 30 44 30 46 30 48 30 4a 67 ff 53 3a 30 00
16: 本 日 は 晴 天 な り
67 2c 65 e5 30 6f 66 74 59 29 30 6a 30 8a

<脚注>
ここで "MS932" などの 『呪文』に関しては、(参考文献*2) をご覧ください。
また 本稿の後半においても補足的な説明を付与します。
</脚注>

このようなデバッグトレース用コードを利用することにより、私たちは 『見えるのに見えない』文字コードを 『'そのまま' 見える』ようにする事が出来ます。それが単純なる事実としての文字コードとして見えてくることにより、発生箇所やその現象が 明快に把握することが可能になるのです。
どこかの書籍やウェブページで偶然見かけた謎の 『呪文』を場当たり的に使ってみるのではなく、まず発生箇所や現象を把握することこそが、文字コード問題のプライマリケアとして適切であると私は経験的に考えています。

バグ

JDKの実装上のバグが原因で 文字コード問題が発生することがあります。
データベースまで範囲を含めて考えた場合に私が一番深刻だったのは JDKやJREに付属するJDBC-ODBC Bridge (Type1) のバグだったと考えています。このJDBC-ODBC Bridgeが 全くのところバグっていて 『ごく普通の』文字が "幾つか" 扱うことができない不具合がありました。この話題は (参考文献*4)でも扱いました。

この不具合は Java2 SDK 1.2.2_005 およびJava2 SDK 1.3 で修正されています。
Java2 SDK 1.2.2_005 の修正情報一覧 (http://java.sun.com/products/jdk/1.2/ja/CHANGES-1.2.2-005.html) の中に Bug Id 4215746 (http://developer.java.sun.com/developer/bugParade/bugs/4215746.html) として見いだせます。
すなわち 1.2.2_005および1.3以降のJDKやJRE付属のJDBC-ODBC Bridgeの日本語関連不具合は既に過去のものになっています。このため、PreparedStatement.setString(...) や ResultSet.getString(...) などが JDBC-ODBC Bridge経由においても 『普通に』 利用することが可能になりました。

脚注
なお JAVA PRESS Vol.8で記載していませんでしたが、SUNのJavaVM以外の目を向けた場合には、以前より Microsoft SDK for Java に含まれる JDBC-ODBC Bridge では 日本語を正常に扱うことが出来ていました。しかし残念なことに この JDBC-ODBC Bridge を取り出して 別の JavaVMで利用することはできないようになっていました。(だから現実問題として 日本語が扱える JDBC-ODBC Bridgeは 無いに等しかったです) この件につきまして、JAVA PRESS 読者の方からお教えいただきました。ありがとうございました。

そもそもORACLEやDB2などのメジャーな商用RDBMSについては 純正JDBCドライバが既に提供済みですので JDBC-ODBC Bridge (Type1) はもはや利用されません。また、それら純正JDBCドライバの最新情報の詳細については、JAVA PRESS Vol.13 JDBCドライバ & SQLJトランスレータ最新情報 秋元康弘 p.27- (参考文献) に 大変詳細で貴重な情報があります。というのも、幾つかのケースにおいては発生した問題の解決のために JDBCドライバのバージョンを工夫する必要があるのです。

しかし 未だに 幾つかのRDBMSについては純正JDBCドライバが提供されていません。こういった場合には 現在でも やはり JDBC-ODBC Bridgeは 必須のツールでして、この不具合修正は こういったJDBC未対応RDBMS利用者にとって朗報です。Microsoft SQLServer7.0を利用する場合が 丁度これに該当しまして、JDBC-ODBC Bridge を使ってODBC経由でアクセスするようにして、初めてJavaからのデータベースアクセスが可能になります。

なお、私見ですが基本的に JDBC-ODBC Bridge で完全に日本語が通るようになったとはいえ、JAVAとは関係ない初歩的一般論として (一般常識として) DBの表名や項目名にむやみに日本語名称は使わない方が良いと考えています。この点は データベース関連従事者の間では 何かと議題に上がりがちです。

それでは JAVA PRESS Vol.8 で JDBC-ODBC Bridge の動作不良を示すためのサンプルソースコードを取り出し、それら修正前後の境界をまたがって動作させてみましょう。
ソースコードの大まかな説明ですが、DbSamp1.java でテーブル作成を行い、 DbSamp2.java でデータベースにデータを入れて、 DbSamp3.java でデータを取りだしてファイルに格納しています。

これの実行について 事前にセットアップが必要です。それら手順を Windows2000 + SQLServer7.0 (+SP2) ベースで説明します。
なお、これら手順に関しましては、テスト用途のテスト専用環境での設定&実行を前提と考えています。(このようなプリミティブな検証作業は本番環境で実行すべきではありません)

ユーザの作成
Microsoft SQL Server 7.0 の Enterprise Manager を使って
該当サーバの [セキュリティ] → [ログイン] で [新規ログイン] で
ユーザ名: user1 パスワード: user1 を作成します。

SQLServer7.0が不明な方のために、、ユーザ作成は下記の手順で作成できます。

ODBC設定の追加

これの実行結果なのですが、JDKのリリースノートに記載されているとおり、

という結果になりました。
異常な現象の詳細ですが、異常な場合には その文字およびその後続の文字が無いものとして扱われてしまうような不具合です。
具体的には 下記の文字が JDK1.2.2-001 では 消失してしまいます。

8140:   (全角スペース)
81cd: ∀
849f: ─
88ea: 一
8b48: 稀
8b49: 紀
8b56: 儀
8cbe: 言
8dc5: 最
8ec1: 蔀
8ef9: 需
91de: 退
9381: 刀
9664: 謀
9678: 堀
9773: 耀
986f: 椀
9a9b: 圀
9cb5: 愀
9cf6: 戀
9db3: 攀
e2c5: 簀
e586: 蜀
ed4f: ?k
ed6c: ??
edb2: ?ホ
eee7: ?F
fa6b: ?k
fa89: ??
face: ?ホ
fc46: ?F

.

【検証に利用したマシンの概要】
フロンティア神代 Frontier FBX333C/98
[CPU] Intel Celeron 333MHz (128KBキャッシュ)
[メモリ] S-DRAM 128MB (8ns)
[OS] Microsoft Windows2000 Professional
[RDBMS] SQLServer7.0 + SQLServer7.0SP2

.

Unicodeのマッピングに対する見解の相違

バグでは無いのですが、結果的にはほとんどバグみたいな事象があります。
シフトJISをUnicodeにマップする際の(もちろんその逆も) マップ位置に関する『見解の相違』に起因する諸問題は一般的にJavaを扱った際に発生する文字コード問題として最も深刻な物だと私は考えています。Java言語利用者にとっては、『"MS932" エンコーディングと "SJIS" エンコーディングとの相違』という扱いでお目にかかることが多いですね。

<コラム的内容>
予め断っておきますが、この問題は そもそも的発想で分類すると、Javaの問題というよりはむしろ Unicodeに関わる問題です。しかしだからといって、ここで性急にUnicodeに対して否定的な考えは持たないで欲しいです。
日本語圏の私たちは、Java言語がUnicodeを採用しているおかげで 欧米のソフトウェアの幾つかを そのまま 日本語版として利用可能だったり 少ない労力の間に日本語版として入手可能になっているのです。その成果として最も印象的なのは JDK自身ですよね。国際版をそのまま日本語版として無意識のうちに利用していますよね。一方 英語圏の人々にとっては Unicodeそれ自身は 多大なオーバーヘッドに他なりません。むしろ2バイト文字圏の私たちのために 約2倍ものオーバーヘッドを受容してもらっているのです。(しかし、どうしても これに耐えられない方々が UTF-8を折衷案として採用しがちな模様です)
</コラム的内容>

私は この問題について '−' (ハイフン文字) において最初に遭遇しました。
ハイフンは シフトJISの際には 817c ですが、一般的なUnicode実装では ハイフンは 2212 にエンコードされてマップされています。ところが マイクロソフト社のWindows98/95/NTのUnicode実装では 'なぜか' ff0d にマップされています。
幸いなことに この一連の相違点は (参考文献*2) p.75-76 に一覧表として掲載されていますし、その説明についても 同書にて解説されています。
個人的主観として『マイクロソフト社WindowsのUnicode実装が異端である』と考えています。また おそらく 私以外の多くの方も 同意見であるでしょう。ところが困ったことに 『Windowsが悪い』の一言で片づけられないのです。Microsoft自身、既存の Unicode対応ソフトウェア保存ファイルの互換性維持という立場がら、Unicodeマップを変更できないのです。互換性維持という観点からは尊ぶべき立ち居振る舞いです。かといって、Windowsおよびその上で動くアプリケーションを無視して「Windowsおよび関連アプリは使うな」とは行きませんよね。というのも Windowsオペレーティングシステムは 現時点では大変に普及してシェアを握っているからなのです。
そうすると Windows上で Windows的Unicodeに対応したソフトウェアを使って Unicodeコードを用いてファイルを保存したとしたら、ここで述べているような数文字は '正しい' Unicodeコードマップを使っては読み込むことが出来ません。('正しい' と囲っているのにも理由があります。というか Unicodeの現状とはこのようなものでして、こちらが正しくてこちらは誤っているとは決めつけることが出来ない状況なのです)
私が経験した 実際の例としては、ORACLEデータベース用 JDBCドライバを使って JavaVM (JDK1.1.7) から Unicode文字列を入出力した際、JDBCドライバからのコードが Windows的Unicodeになっていて これを JavaVM側で "SJIS"的Unicode (つまり'正しい' Unicode)で読み書きをした際に ? 文字になってしまうというものです。
(この件に多少関連するORACLE社の資料は 『NLS環境におけるキャラクタの整合性の問題』 http://www.oracle.co.jp/download/jdbcodbc/jdbc80405/nlsalart.html に見いだすことが出来ます。)

このような経緯があったので、 Windows版のJavaVM は 1.1.7までの時代には "SJIS"エンコーディングをデフォルトとしていたものを、1.2.x (および 1.1.8)からは "MS932"エンコーディングをデフォルトとして採用してしまいました。これのおかげで 1.2.x以降のJavaVMでは Windows的Unicode実装なソフトウェアとの親和性がかなり向上しました。しかし、独断と偏見の上に立ってこれを表現すると『正しかった実装を 現実路線として 仕方なく WindowsのUnicodeに合わせてしまった』ですね。敢えて '間違った' 実装である WindowsのUnicode実装に合わせてしまったのですもの。
このようなことなので、例えば XMLなどを利用してB2B的に 異なる企業間でデータをやりとりする際には その相違点そのものに対して 異常が発生するといった事が予想されます。こういった事象の予防のためにも、エンコーディング指定は デフォルトに任せずに 都度設定して利用するのが望ましいです。また (参考文献*2) にも同様の意図の記載がありますね。
デフォルトに任せずに自分でエンコーディング指定を行うべきものとしては、 Reader,Writer, そして byte[] と String との相互変換などが主なものです。コンストラクタや変換指定などの際に エンコーディング指定ができるようになっています。

なお "MS932"エンコーディングに関しては JDK1.2以降のみならず、JDK1.1.x系においても JDK1.1.8から JDK1.2の"MS932" と同様のものが実装され出しました。この件に関しては JDK1.1.8における不具合修正点一覧に記載されています。http://java.sun.com/products/jdk/1.1.8/fixedbugs.html

なお "MS932"エンコーディングが利用できるようになったおかげで ORACLEなどのJDBC対応なデータベースを利用する場合において、ほとんど日本語問題は出なくなっっていると私は考えています。逆に言うと "MS932" エンコーディングが利用できない環境下では 何かしら小技が必要になります(後述します)

ShiftJISに対する見解の相違

これについても、バグと見解の相違との境界線上のような話です。(内容の性格上、バグとは言い切れません)
まずはJava言語以前の話題から入らせて頂きます。

背景として考えるにあたり、最初に シフトJISそのものを考えてみましょう。その名の如く『JISをシフトさせたもの』 であるという認識が 最も適切であるように思われます。なぜシフトさせる必要があるのかという点については (参考文献*1) をご覧ください。
ところが、困ったことに そもそもJIS自身には 複数のバージョンが存在します。(78年版、83年版、90年版 そして97年版が存在しています) 様々なメーカーのOSは そのバージョンによっても 対応しているJISのバージョンが個々で異なる場合もあります。そのようなことなので、どの版のJISをシフトさせたのかについても注意を払う必要がありますね。ただし 幸いなことに このパターンの文字コード問題は '古典的' になりつつはあります。そして シフトJISのリファレンスとしては JIS X 0208:1997 が使われることが多いようです。

むしろ問題なのは JISで定義されていない文字をどのように扱うのかという それとは別の問題です。というのも、これまた ここ最近良く使われているクライアントOSであるマイクロソフト社の Windows98/95/NT オペレーティングシステムの シフトJISの実装が 『JISでは定義されていない文字が利用できる』 という事実に起因します。JIS X 0208 で定義されない文字が Windowsでは使えてしまうのです。
具体的には、?@ や ?[ や ?? などです。(それ以外にも たくさんあります) これら文字は 『メールで使うことが許されない文字』としても知られていますよね。この件に関する詳細については 古場 正行さんの『情報交換用漢字符号系 JIS X 0208 』 (http://www.noge.com/koba/network/mail/JIS-X-0208.html) に詳しく見ることが出来ます。
(ちなみに、そのページ自身は 『日本語フォントや文字コードについて』 http://www.zukeran.org/shin/jdoc/ からたどっていきました)

この問題についても 『そんな文字は使うな』の一言で片づけることができればそれに越したことはないのですが、そうは行かず なかなかに根が深く そして JavaVMの実装にも影響を与えています。そして この問題が ちょうど 前述の "SJIS"エンコーディング と "MS932"エンコーディング とに現れています。すなわち "MS932"エンコーディングでは これら Windowsで 'JISには無いのに使えてしまう' 文字列が Windowsの実装に忠実に合わせて提供されています。'正しい' "SJIS"としては扱うことが出来ないのですが、Windows的"MS932" としては これら未定義文字が Windowsに忠実にUnicodeにマップ実装されています。"MS932"エンコーディングを使うと これら ?@ や ?[ や ?? などが 'すんなり' 利用することができます。

そのような状況でして、これら問題に関しては 場当たり的には改善されているものの、本質的には何ら改善されていません。例えば XMLが今後 劇的に流行した際に この問題は強く顕在化することと私は心配しています。

デフォルトエンコーディングの調査方法

以前の箇所で書きましたが、Java2 SDK 1.2 および JDK1.1.8から、デフォルトエンコーディングが "SJIS" から "MS932" に変更されました。
このことは 下記のサンプルプログラムで確認を取ることが出来ます。

MdDefaultCnv.javaへのリンク

このサンプルの SUN Java2 SDK 1.3 Windows版の WindowsNT4.0上での実行結果は下記のようになります。.

> java MdDefaultCnv
ByteToCharConverter: MS932
CharToByteConverter: MS932

このプログラムは Windows環境下においては、Java2 SDK 1.2以降では "MS932" が戻りました。JDK 1.1.6 では "SJIS" が戻りましたが、JDK1.1.8では "MS932" が戻りました。(よもやと思いましたが なんと JDK1.1.8のデフォルトエンコーディングは "MS932" なのです)
こういったことも ソースコードが閲覧可能だと調査できるので嬉しいですね。
(ただし このサンプルで例示しているデフォルトエンコーディングを取得する方法は、実際の現実的なプログラムの中で利用するのはお薦めできません。というのも sun.io パッケージは javaパッケージなどとは異なり 以降のバージョンでの互換性が保証されないからです。そのため私は デフォルトエンコーディングを用いずに明示的なエンコーディングを利用する場合には その値をプロパティファイルなどに格納しておくことが多いです。)

一覧表

基本的に SUN の Windows版JDKをベースに記載しています。

1.1.7以前 1.1.8 1.2 1.2.2_005以降 1.3
デフォルトエンコーディング SJIS MS932 MS932 MS932 MS932
MS932エンコーディングのサポート ×
JDBC-ODBC Bridge内での日本語正常動作 × × ×

この調査は SUN Windows版の JDK1.1.6 , JDK1.1.8-004 , Java2 SDK 1.2.2-001 , Java2 SDK 1.2.2-006 , Java2 SDK 1.3 を利用しました。

インターネットに不向きな文字(および文字コード)

これも プログラミング以前の話なのですが、異機種相互接続といった観点から インターネットには向いていない文字(文字コード)が存在します。これは 以前の箇所で JIS X 0208 のことを扱った際に取り上げた話題と ほぼ同一です。一口で言うと 『JIS X 0208 で定義されていない文字は使わない』 ということです。これに加えて 半角カタカナ も 諸般の事情により インターネット上では 扱わない方が良いとされています。JIS的にも 半角カタカナは推奨されなくなってきています。

それに加えて インターネット技術 (well known portsの実装) の特性ゆえに そこを通るデータは 多くの場合 7bit範囲内に収める必要があります。古典的な実装ではバイトストリームのデータとして その最上位ビットは 0 であるように要求されるのです。最上位ビットは バイナリデータやシフトJISなどで利用されていますから、これを無理矢理7bit化するために MIME Base64化などのエンコード技術が別途利用されます。
なぜ そのような事に言及するのかというと、Java Servletを用いて WWWブラウザとの間で交信する際に 時として この問題が浮上する場合があるからなのです。あるWWWブラウザでは そのページ自身が記述されている文字コードを優先して WWWサーバ側に文字列を送信するような実装をされている場合があるように聞き及びます。そうすると WWWページ自身を 7bit化された何かしら文字コードを利用すべきとのルールなどが必要になる場合もあるでしょうし、他方 サーバ側では 受信したデータが いったい何の文字コードで表現されたデータであるかを知るために 本稿のはじめの方にかかれたデバッグトレースの手法を適用する必要が出てくるかも知れません。

私は Java Servletに関しては あまり経験が無いので 個別の具体的な実装の差異などは存じませんが、少なくとも それら文字コード問題が発生した場合には、基本的な原則に従って 文字コードの調査のために デバッグトレース手法を活用すべきと考えていますし、実際にそれは効果的なのだと考えています。(調査して現象を理解した上で "ISO2022JP" や "ISO8859_1" などを使うのが 結果的に近道なのです)

文字コード一覧の作成(取得)方法

本稿の最初の方で述べたデバッグトレースは 文字コード一覧表が手元にあってこそ その現状を分析&把握することができます。その文字コード一覧表自身は 出版物の形式で入手できる場合もありますが、本稿で扱っているような "MS932"エンコーディングUnicodeコード一覧表 や "SJIS"エンコーディングUnicodeコード一覧表などは 自ら作成しないと 他に入手経路が無い場合もあります。
自ら作成する手法は古典的で一般的な手法でして、本稿でも 簡単にその手法を紹介いたします。(参考文献2にも一覧表が付属します。併せてご覧頂ければなお幸いです。)

Windowsの文字コード(シフトJIS) 一覧作成方法
これに関しては さすがにJAVAで記載せずに C++で記述しました。といっても ソースコードは JAVA PRESS Vol.8 で利用したものと全く同一です。
main.cpp
含まれるプロジェクトファイルは VisualC++用です。これをコンパイル&実行すると 下記のような一覧表が出力されます。

(一部分抜粋)
88a2: 阿
88a3: 哀
88a4: 愛
88a5: 挨
88a6: 姶
88a7: 逢

では 続いて JavaVMの Unicode実装や エンコーディング実装について文字コード一覧を作成します。今度はもちろんJAVAでプログラミングしました。
MdUnicodeList.java
コンパイルして実行すると下記のような一覧表がファイル出力されます。

(一部分抜粋)
611a: 愚
611b: 愛
611c: ?
611d: ?
611e: ?
611f: 感
6120: ?チ
6121: 愡

Unicodeの方に関しては 未マップのものは敢えて "?" で出力してみました。Javaのエンコーディング実装の方に関しては "?" の出力は抑制するように作ってみました。ただし ソート順を Unicodeベースで行ったので、シフトJIS的に閲覧する場合には ちょっと見づらいかも知れません。そのような際は ソートしなおすか 生成プログラム側を変更してみてください :-P

文字コードは 文字のコードですので、このように単純なループを用いるだけで一覧が作成できます。便利ですね。

対処技

いくら最新バージョンや最新リビジョンなどでバグや問題が解決されているからといっても、それを適用できないケースも結構あるものです。また 幾つかの問題は 最新バージョンにおいても残存していることもあります。
データベースアクセスやHTTP通信などの際の文字エンコーディングを用いた対処方法は JAVA PRESS Vol.13 実践! Web+DB 連携アプリ開発のポイント 菊田英明 p.21- (参考文献) に '最新の' 対処技を見ることが出来ます。

それ以外のケースの対処方法として ごく簡単に MS932エンコーディングのUnicode と SJISエンコーディングのUnicodeとの相互マッピングのサンプルコードを例示したいと思います。
一般のUnicodeマップ (具体的には "SJIS"エンコーディングを用いた際の Unicodeマップ) を Microsoft Windows的 Unicodeマップ (具体的には "MS932"エンコーディングの Unicodeマップ) に変換するサンプルソースコードを例示します。
MdUnicodeCnv.javaへのリンク
ただし このサンプルコードは あくまで例示を目的としています。ソースコードを見ての通り、対応する文字コードは  ̄ , 〜 , ‖ , ¢ , £ , ¬ , −だけです。この手法は ORACLE + "SJIS" エンコーディングの際に必要になる場合があります。

さいごに

多量に文字コードに関わる問題が書いてあり うんざりされた方もいらっしゃることと思います。(実際 私はうんざりしました)
しかし 私はむしろ それら文字コードや日本語にまつわる諸問題が 冒頭で挙げたような諸資料によって、既に明らかになっていたり バグフィックスや変更などにより問題解決されているというということに注目しています。みなさんにも その点を理解されることを祈っています。そして この記事自身が 新たに文字コード問題に遭遇してしまった方々への 『プライマリケア』となってくれればと願っております。
また そもそも この記事は 必要な人のみが 読んでいることでしょう。ほとんどの人には必要のない、、、ことなのかもしれませんが、しかし この文字コード問題は 困ったときに初めて気にする問題でして、なおかつかなり面倒で気にもかけたくない問題なのです。
しかも 文字コード問題は、JAVA言語のみならず、例えば 他の言語を用いて XMLだけに関わっている時ですら、遭遇してしまう問題なのです。(むしろ文字コード対応機能を言語として実装していない環境で 文字コード問題に対処するのは至難の業でしょう)

本記事は 隔月刊行の媒体に載るという形態ゆえに、『今まさにホットな内容』が書けたことと自負しております。JDK1.3やJDK1.1.8などの カレントな内容が織り込めたのが 何より幸いです。一方 時事問題を扱った故に 誤りが混入する恐れも大きく その点に関しまして読者のみなさまのご理解が得られるよう こちらも祈っております (苦笑)

この記事が JAVA言語やXMLの普及に少しでも寄与できることを祈りつつ 筆を置きたく存じます。

サポートページ
更新履歴

midori.iga@nifty.ne.jp
$Date: 2008/05/24 06:22:39 $