Open Source WEB

文字化け

文字化けは、日本語を扱う限り、最も注意しないといけない。 データベースでは文字が化けてしまっては最悪である。 些細な文字化けだし、見れば意図していることは分るではないかという 考え方は危険である。 データは人間が見ている間はそれでも良いかもしれないが、 そのデータを利用して自動的に様々な処理を行なうようなことを 必ず行なうようになるので、些細なことが大きなトラブルに繋がってしまう。

MySQLも、いろいろ調べていたら、どうも文字化けというか、 勝手に文字を変更してくれることがある。 今回から、そのあたりを旅してみようと思う。


サーバ側(sjis) - - - - クライアント側(sjis)

端末の文字コードを Shift-JIS にして、以下を行なってみた。

mysql> SET NAMES sjis;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT '\\';
+----+
| \ |
+----+
| \  |
+----+
1 row in set (0.00 sec)

SET NAMES で使用するキャラクタセットを端末に合わせて シフトJISにした。

そして \(端末がSJISなので、半角の¥マーク)だけの文字列を試してみると、 不思議なことになってしまった。 上側は全角の逆スラッシュ、下側は¥マークになったのである。 (\は使用しているブラウザの設定によって見え方が変るかも)

それにしても、なぜ上だけが全角の\になってしまうのか。

'\\' と \ が2つ続いているのは、\ はエスケープになるので、 もう1つ書かなければならない。エスケープの意味については説明するのが 面倒なので、知らない人はどこかで調べて下さい。

さて、文字列がどうなっているか分らないときにやるべきことは、 HEX()を使って16進数表示するのが常套手段である。

mysql> SELECT HEX('\\');
+-------------+
| HEX('\\') |
+-------------+
| 5C          |
+-------------+
1 row in set (0.00 sec)

ますます怪しいことになってきた。 SELECT HEX('\\') というSQL文をMySQLサーバに送ったのだが、 上の段は、HEX('\\') というとんでもない表示になってしまった。

どうも、\ は \ になってしまうようだ。

現在のキャラクタセット関連のシステム変数を見てみよう。

mysql> SHOW VARIABLES LIKE 'character\_set\_%';
+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| character_set_client     | sjis   |
| character_set_connection | sjis   |
| character_set_database   | latin1 |
| character_set_results    | sjis   |
| character_set_server     | latin1 |
| character_set_system     | utf8   |
+--------------------------+--------+
6 rows in set (0.00 sec)

とくに異常はないようだが、摩訶不思議な変換をしてくれる。


サーバ側(ujis) - - - - クライアント側(sjis)

mysql> SET character_set_connection=ujis;
Query OK, 0 rows affected (0.00 sec)
 
mysql> SHOW VARIABLES LIKE 'character\_set\_%';
+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| character_set_client     | sjis   |
| character_set_connection | ujis   |
| character_set_database   | latin1 |
| character_set_results    | sjis   |
| character_set_server     | latin1 |
| character_set_system     | utf8   |
+--------------------------+--------+
6 rows in set (0.00 sec)

これで、サーバ側が ujis で、クライアント側が sjisになった。 クライアント・サーバ間でキャラクタセットが異なると、その間を 文字が移動するとき、ありがたいことに、ちゃんと変換してくれるのである。

さて、もう一度変換してみよう。

mysql> SELECT '\\';
+----+
| \ |
+----+
| \ |
+----+
1 row in set (0.00 sec)

こんどは、上も下も全角の \ になってしまった。

どうも今日は mysql の御機嫌が斜めなのか、訳の分らない変換を施してくれる。 また日を改めて調べることにしよう。


戻る:UNHEX()で16進数表記から文字列を作る

次へ:バックスラッシュ(\,5C)が文字化けする(続編)


フィードバック:

Name:
Comment:
shiro: (Thu Jun 2 12:08:05 2005 )
ついでに '~' を調べてみるどうなります?

Shift JISのコード0x00〜0x7fは厳密に言うとASCIIではなくJISX0201 (JIS-Roman) なんです。ASCIIとJIS-Romanは御存じの通り0x5cと0x7eに割り当てられている文字が異なります。これは「フォントの違い」などではなく、そもそもASCIIとJISX0201ではコード0x5cの意味が違うんです。

伝統的に日本のコンピュータ使いは、これら異なる文字をあたかも同じ文字の別表現であるかのように読みかえてきました。それで問題無かったし、JISX0201環境で作ったCのソースがコンパイルできなかったら困りますしね。

ところが、ASCIIやShift JISをUnicodeへ変換しようとした時に、困ったことが起きます。Unicodeは0x5c, 0x7eで異なっていた文字を両方とも含んでいるので、変換時に例えば0x5cに出会った場合、それがASCIIのコンテキストで起こったのかJIS-Romanのコンテキストで起こったのかで異なるコードへとマッピングしなければなりません。問題は、このマッピングテーブルが統一されていないことです。さらに、2つ以上のエンコーディングを経由して変換していった場合に、最後に同じコードに矛盾無く戻って来れる保証がありません。

0x5cだけに関して言えば、Shift JISではなくcp932というエンコーディング (WindowsはShift JISと言われていますが実はcp932) ならばそのままU+005cに素直にマップしてくれるんじゃないかと思います。
fuji: (Thu Jun 2 14:27:57 2005 )
'~' もおかしくなりすね。
これは、'\\'の次のネタということで。

昔、日本国内でCコンパイラが法外な値段で得られていたので、直輸入して、
コンパイルが通らない日本語の部分全部に \ を挿入してしまうフィルタを
作って動かしてました。

このサイトは、 IPA の「平成15年度オープンソフトウエア活用基盤整備事業」 の委託事業として開発されたKahuaで試験的に運用しております。

Copyright (c) 2004-2007 株式会社タイムインターメディア About Us