Beginner's Rock Official Website

犬土偶日記

海の近くに住みたい

BR日記の使い方

話題:Webプログラミングとか

2006年01月06日

文字コードという名のウンコ

公開日時: 不明

ずいぶん前から言ってるが、日記のCGIを自分で作り直そうと思っている。今まで思ってるだけで一向に手を出す気配も見せなかったが、実は最近少しずつ作り始めてたりする。そのことについて書いてみようと思う。プログラミングとかやったことない人には全然理解できなくて面白くないかもしれんが知ったこっちゃない。思わぬところで苦戦して密かに歯を食い縛ったのです。まず、今使ってるこの日記CGIは他所で無料で配布してるスクリプトだ。それを少し弄って改造して使っている。このCGIはPerlで書かれてるのに何故か文字コードがShift_JISだ。ログファイルも画面への出力も全てShift_JISだ。一般的にPerlのCGIはEUC-JPで書く。何故かというと、Shift_JISの一部の文字の2バイト目にPerlのエスケープシーケンスの\と同じコードが含まれている文字があって、その文字の次の文字の1バイト目が強制的にエスケープされてしまうという問題があるからだ。どの文字でそうなるのか知っていればその文字の後に\を書いて\自体をエスケープして逃れることができる。だが激しく面倒だし漏れがあるといけないので普通は最初から何の問題もないEUC-JPを使う。ネット上で無料で配布されているCGIにShift_JISが多いのはたぶんEUCに対応してるテキストエディタを用意できないかもしれない初心者を考慮してるんだろうと思う。これが実に鬱陶しい。俺が新しく作るCGIは当然EUCで書くことになるんだが、既に書かれた過去の日記のログファイルはShift_JISだ。これを全てEUCに変換するのは大変なので、ログの入出力はそのままShift_JISで、画面への出力だけEUCにしようと思っていた。そして問題発生。

自分の日記のログを使って、目次や日記を表示する部分のプログラムを実行してみたりしてた。既に表示する部分はできている。最初は全く問題ないように見えた。なかなかいい感じだ。しかしじっくり見てみるとところどころおかしい。文字化けが発生している。ミキティのAAが確実に化けている。いろいろ弄ってみたがどうしてもダメだ。jcode.plで文字コード変換してみても上手くいかない。というかEUC-JPでミキティのAAを表示できない。

<html>
<head>
 <meta http-equiv="Content-Type: text/html; charset=EUC-JP">
 <title>ミキティAA</title>
</head>
<body>
 <p>川v)</p>
</body>
</html>

これをブラウザで表示するだけで文字化けしてしまう。もちろん保存時の文字コードはEUCだ。ブラウザでエンコードを変えようと思ってもちゃんとEUCで表示されている。おかしい。

print "Content-Type: text/plain; charset=EUC-JP\n\n";
print "川v)\n";
exit;

こういう簡単なプログラムをPerlで書いてCGIで実行してみた。これすらも表示できない。HTTPヘッダで文字コードを指定したテキストですら文字化けする。おかしい。もしかしてEUCにはミキティAAの目の部分に使われてる文字が存在しないんじゃないだろうかと思った。そう言えばGoogleでミキティAAを検索するとほぼ確実に文字化けしてるしな。それで、2ちゃんの狼の美貴スレでEUCでミキティAAを表示する方法知らない?もしかして目の点はEUCには存在しないの?って聞いてみた。どうやら存在するらしい。でも俺にはどうやってもEUCで表示できない。誰かがサンプルとしてEUC-JPで書かれたHTMLにミキティのAAを入れてUPしてくれた。確かにEUCで表示できている。おかしい。試しにその美貴AAをさっきのHTMLやCGIにコピペしてみた。そしたら何故か上手く表示できた。おかしい。今度はダメだったAAと表示できたAAを並べてコピペしてみた。片方だけ化けた。見た目は同じなのに。全く同じ目の点だけを並べて表示して片方だけ化けるということは、見た目は全く同じでも中身は完全に別の文字ということだ。そもそもミキティAAの目の部分の入力の仕方を知らない。「きごう」「てん」「’」とかで変換しようとしても絶対に出てこない。どうやって打ち込むものなのか全く分からない。だから使う時はコピペしてたんだが、コピペ元は2ちゃんに違いなく、すなわちその時点でShift_JISで書かれたAAだったということになる。同じように見える文字がEUCに存在するとしてもShift_JISで書かれたそれをそのままEUCで表示しようとしても無駄ということだ。jcode.plでも変換できないならお手上げ。ログファイルを全て手書きで修正すれば解決するが、700日分以上もある日記を全てチェックするのは不可能に近い。それに、たまたまミキティAAの目の部分だけ気付いたが、他の文字でも同じようなことがあるかもしれない。だからShift_JISで書かれているログをEUCで表示するというのは危険なのでやめておいた方がいい。それにEUCに変換してしまったら今後また困ることになるかもしれない。携帯電話に対応しようと思ったら文字コードはShift_JISにしなければならない。絶対ではないが、Shift_JISしか表示できない携帯が多いらしい。その時に今と全く同じだが逆方向の問題が発生することになる。とりあえず色々考えると表示部分もShift_JISにするのがいい。だが、それだとまた別の問題が発生する。プログラムはEUCで書かれている。つまりプログラム内に書かれているprint文の中の日本語はEUCなのだ。それを出力時にイチイチShift_JISに変換しなくてはいけない。例えばこういうこと。

open (LOG, "./log.txt"); #ログファイル(Shift_JIS)
$sjis = <LOG>; # $sjisにログファイルから1行取り出して代入
close (LOG);

print "うんこ:$sjis"; #「うんこ:」はEUC、$sjisはShift_JIS

exit;

このままだと確実に化ける。これを化けさせずにShift_JISで表示するためにはこうしないといけない。

require "jcode.pl";

open (LOG, "./log.txt");
$sjis = <LOG>;
close (LOG);

$euc = "うんこ:";
jcode::convert(\$euc, 'sjis', 'euc'); # $eucをEUCからSJISへ変換
print "$euc$sjis";
exit;

たったこれだけのことなら何も問題はない。例えば目次のページを出力する時を考えてみよう。ログファイルは「日付8桁数字<>タイトル<>本文・・・」という形式で記録されている。ここから日付とタイトルを抽出してそれをアンカーにしてリンクのリストを生成する。「○年○月○日 タイトル」という文字列をアンカーにしてログファイルから1行ずつ抽出して生成していくことになる。日付は半角数字だから化けることはなかろう。タイトルはログから抽出した文字列だからShift_JISだ。そのまま出力すると、Shift_JISとして出力しても文字化けしてしまう。なぜかというと、「年」「月」「日」の部分がEUC-JPで書かれているからだ。ならばどうするか。簡単に思いつく方法は2つ。$year = "年"; $month = "月"; $day = "日"; jcode::convert(\$year, 'sjis'); jcode::convert(\$month, 'sjis'); jcode::convert(\$day, 'sjis');としておいて、「○$year○$month○$day タイトル」という形で出力。これは激しくカッコ悪い。みっともない。$date = "○年○月○日"; jcode::convert(\$date, 'sjis');として「$date タイトル」を出力する方がスマートに見える。だがこれだと日数と同じ回数jcodeのサブルーチンを呼び出すことになる。当然処理は遅くなるだろうしサーバーの負荷も大きくなるだろう。体感的にはほとんど変わらないだろうとは思うが。何にしても文字化けは全て潰さねばならない。ただ読めなくなるだけではなく、表示されるページ全体に悪影響が出る。例えば文字化けがA要素の終了タグを巻き込んだりしたらそこから次のブロック要素が出現するまでの全ての要素がアンカーと認識されてしまう。まぁ読めないのも問題だけどな。

深夜にこんなことを考えながらダラダラとプログラミングしてたら急激に腹が減った。年末に少し食料を買っておいたが、あまりにも高かったので必要な分を買い込めなかった。だからとっくに食料は尽きている。さすがに米だけではもうそろそろ限界なので何か買いに行こうと思った。夜型生活なので昼まで起きててGENKYに買いに行くとかいうのは無理だろう。仕方がないのでコンビニに買いに行った。コンビニは極悪だな。どう考えてもボッタクリ。なんであんなに高いんだ。寒さと値段の高さで気を失いそうになりながら帰宅。そして絶叫。何故かPCの電源が落ちていた。エアコンも切れていた。電気の消費量が多くなり過ぎると自動的に切れるようなOAタップを使ってて数年に一度これが発生する。雷とかの対策のためについてるのかもしれない。詳しいことは分からん。何でこんな目に遭わねばならんのだ!うちのPCは電源切れると復活しなくなることがある。ガクガク震えながら主電源を切って数分待ちながら飯を食った。それから電源ON。復活した。よかった。いや、よくないかもしれない。プログラム中の日記CGIを最後に保存したのはいつだっただろうか。文字化け対策であれこれ試しながら実行してたから結構頻繁に保存してたはずだとは思う。エディタを起動してみた。見てもハッキリとは分からんが、たぶん大丈夫。でもやる気が失せた。というか眠くなりすぎた。寝た。

夢を見た。椅子タンの車に乗ってて事故る夢。道路が凍ってるのにすげぇスピードで走りながらドリフトしたりして嬉しそうな椅子タンとアホみたいに怯える俺。ちょっと前に雪で滑ってバイクで転倒した恐怖が脳に染み付いてるんだろう。細い道でもスピードを落とさず走ってたら向こうからデカいトラックが来た。避けれるはずはないが道から少しはみ出す感じで行けば大丈夫かもしれない。いや、無理だ。と俺は思ったが椅子タンは自信満々。でもトラックが俺たちと同じ方向へ避けた。死ね!もう間に合わん。横の民家の車庫に勢いよく突っ込んだ。トラックはそのまま逃げた。俺は何故か衝撃も感じることなく無傷。椅子タンはどういう状況かわからんが柱に打ち付けられてた釘の頭にデコをぶつけて半分気絶したみたいになってた。その家に入ってみたら無人だったので夕方までそこでくつろいでたら家の人が帰ってきた。何故か椅子タンの親だった。まだ続きもあったし、一度途切れて別の夢も見たが忘れたので書かない。

21時半ぐらいまで寝てた。どんどん起きてる時間がズレていく。とりあえず途中で投げたプログラミング再開。文字化けに関しては、上の方で挙げた2つ目のパターン(jcode::convertを日数分呼び出す方法)でとりあえず放置。これは後回しにする。文字化け問題はとりあえず解決。今のところ化けてる気配はない。検索、コメント、書き込み、ナビゲーション、書き込み時ログ整形、表示時ログ整形、アクセスログ、画像アップロード、あと他に何か要るかな?適当に作っていこう。今月中には完成するんじゃないかと思う(訳:年内にできたらいいな)。ところで今日は何曜日だ?ちゃんと毎日日記を書いてるつもりでいるが、もしかして1日に2回日記を書いたりしてるかもしれない。今日の日記の日付が1月6日になってるが今日が6日だと確信できない。今日が6日なら明日はバンドの初練習か。今日は早めに寝ないと練習の時間に起きれんな。19時半までには起きてないとヤバい。なかなか難しい。

話題:Webプログラミングとか

Info.
公開日時不明
本文文字数5404文字 (タグ込み)
URLhttps://orca.xii.jp/br/diary/diary.cgi?id=dogoo;date=20060106
Comments

コメントはありません。

コメント投稿フォーム
文字色              
  • 名前を省略すると「名無しBeginner」になります。
  • メールアドレスの入力は任意です。
  • 海外からのコメントスパム対策のため、表示された漢字の読みを必ず入力してください。
  • 本文は必須項目です。投稿する場合は必ず記入してください。タグは使えません。
  • 改行が1つ入力された場合は強制改行として処理されますが、2つ以上連続する改行は段落の終了として処理されます。
  • 本文の行頭に「>」のある文は引用としてマークします。引用でない部分の冒頭に「>」は付けないでください。
  • コメントの削除は管理者若しくは日記執筆者しかできません。書き込む時は注意しましょう。
  • 全部記入が済んだら投稿ボタンを押す前に一度読み直して推敲しましょう。