≫文字コードについて
皆さんがお使いのコンピュータとそのソフトは、たぶん何も気にすることなく日本語を扱うことが出来ると思いますが、ここまで来るまでには実はいろいろな困難を乗り越えてきています。
なぜかというと、もともとコンピュータはアメリカで発達してきたので、アルファベットや数字以外の文字を扱えなかったのです。日本語の文字数は、英語のそれとは比べ物にならず、英数記号を表すのに1バイトで事足りていたものが、日本語では2バイト以上が必要なのです。さらに、かなと漢字の変換など厄介ごとが実に多い言語でした。
そこで、日本語の文字を扱うべく(変換などは別として)文字コードが設定されているのですが、これが不幸なことに複数あり、それぞれ正しく認識できないと文字化けという現象が発生するのです。
Perl で スクリプトを組んでいこうとした時、けっこうややこしいコトなのに初歩的な段階でぶち当たってしまうのが、この文字コードの問題です。
ただ、わかってしまえばそれほど難しい問題ではないというのも事実かもしれません。以下に、Perl で CGI を組むのに知っていておくべき知識を記しておきますので、ご参考になれば幸いです。
複数の文字コードが存在することを実感する場面と言えば、インターネットサイトをブラウズしているときに文字が化けた時ではないでしょうか。IEにしてもNetscapeにしても日本産のソフトではないからか昔から文字コードの判別には苦労が伺えます。これはサイトを構築する側が明示的に文字コードを表さないということも影響していますが。
ソフトが、ある文字コードを別の文字コードだと認識して表示すると、さっぱりわけのわからない文字が表示されます。やたら画数の多い漢字ばかりだったり□だらけだったり、これがいわゆる文字化けです。(エキスパートともなると、化けた文字列を見て元がわかるらしい)
では、代表的な日本語文字コードを紹介します。
で、突然ですが、Perl で CGI を組む場合は EUC コードで記述するのが賢明です。
なぜかと言えば、Perl で文字列のマッチング処理や置換処理を行う際に、EUC 以外のコードでは厄介事が発生してしまうのです。原因は EUC 以外の文字コードには、perl が特別な意味として解釈してしまう文字が含まれているからです。EUC にはそのような文字がありません。したがって、スクリプトは EUC で記述するのがトラブル回避の第一条件となります。
ただし、配布用の CGI ではそうは行きません。世の中のユーザのほとんどは Windows であり Mac なのです。それらの OS は基本的にシフトJIS を標準文字コードとして利用しており、付属のテキストエディタもシフトJIS でしか処理できなかったりします。
そういう理由から、当サイトでは一部スクリプト以外は シフトJIS で組んであります(処理的にも面倒くさいことしてたりする…)。今の所、そのことによる問題というのは発生していないと思いますが、処理的には無駄な部分にも思えてたりもします。
最終的にスクリプトの文字コードを何にするかというのは別として、CGI を組む際に注意しておくべきなのは、文字コードを統一するということです。
CGI でブラウザから送られてくる文字情報に関して、文字コードを確定することは出来ません。CGI で受け取って文字コードを判別する手はありますが、受け取る際に何の文字コードで送られてくるかということはわかりません。ブラウザの挙動に依存しています。
従って、CGI で情報を受け取ったら、まず一意の文字コードに変換する必要があります。
Perl で文字コードを変換する際は jcode.pl というライブラリを使用します。使い方については、jcode.pl の私的な解説書が詳しいです。他そこら中の配布スクリプトで使われていると思いますので、ソースを覗けば具体例もいろいろと見つかると思います。
最近は Jcode.pm という Unicode 対応のモジュールも開発され、base64 エンコード(メールヘッダに日本語を使う場合に必要な処理)も簡単にできるなどなかなか便利そうですが、私もまだあまり使ったことがありません。公式サイトによると Perl5.8 より Perl 標準装備になるそうなので、文字コード変換のスタンダードになる日も近いみたいです。
ちなみに、UNIX では、古くから nkf という文字コード変換フィルタがありますが、プロバイダのサーバスペースやレンタルサーバのスペースなどでも、環境によって使えなかったりすることが多いので、配布スクリプトや UNIX ユーザ以外には jcode.pl の方がメジャーなようです。
スクリプトの文字コードは、スクリプト自身の文字コード、CGI で受け取る段階での文字コード、変数に格納されている状態での文字コード、出力する文字コードといくつかの状態を意識しないといけません。
例えば、
この処理が書かれたスクリプトの文字コードが JIS もしくは シフト JIS だとエラーが発生し、正常に実行できません。
シフトJIS で記述して、マッチ部分をエスケープして、
もうひとつ、シフトJISで以下のような処理をしたとします(Perlメモより)。
$str = 'テスト'; のときに $keyword = 'X'; でパターンマッチを行なうとマッチしてしまうのです。なぜかというと、シフトJIS の「ス」の文字コードに「 X 」の文字コードが含まれているからです。細かくは解説しませんが、このようにアスキー文字のコードを含む日本語文字は組み合わせによってかなり多く、シフト JIS で書かれた上記マッチ判定処理はうまくいきません。
これらのような、JIS やシフト JIS で記述されることによって起こるマッチ処理や置換処理の不具合は、EUC コードで記述することで簡単に解決できます。
もしくは、マッチ処理や置換処理の際に毎度変数を EUC に変換して処理をするという手もないことはないのですが、面倒くさいです(doBOARD ではそれをやっていますが)。
ウィンドウズのメモ帳をテキストエディタにしていると、文字コードが複数あるということすら気にしないかもしれませんが、Perl スクリプトを記述する上では、日本語文字の処理の際にどうしても文字コードの問題が立ちはだかります。そんな時、まず第一にやるべきことは、スクリプトを EUC で記述する。CGI で受け取った情報は EUC に統一する。という2点です。
なぜかというと、もともとコンピュータはアメリカで発達してきたので、アルファベットや数字以外の文字を扱えなかったのです。日本語の文字数は、英語のそれとは比べ物にならず、英数記号を表すのに1バイトで事足りていたものが、日本語では2バイト以上が必要なのです。さらに、かなと漢字の変換など厄介ごとが実に多い言語でした。
そこで、日本語の文字を扱うべく(変換などは別として)文字コードが設定されているのですが、これが不幸なことに複数あり、それぞれ正しく認識できないと文字化けという現象が発生するのです。
Perl で スクリプトを組んでいこうとした時、けっこうややこしいコトなのに初歩的な段階でぶち当たってしまうのが、この文字コードの問題です。
ただ、わかってしまえばそれほど難しい問題ではないというのも事実かもしれません。以下に、Perl で CGI を組むのに知っていておくべき知識を記しておきますので、ご参考になれば幸いです。
複数の文字コードが存在することを実感する場面と言えば、インターネットサイトをブラウズしているときに文字が化けた時ではないでしょうか。IEにしてもNetscapeにしても日本産のソフトではないからか昔から文字コードの判別には苦労が伺えます。これはサイトを構築する側が明示的に文字コードを表さないということも影響していますが。
ソフトが、ある文字コードを別の文字コードだと認識して表示すると、さっぱりわけのわからない文字が表示されます。やたら画数の多い漢字ばかりだったり□だらけだったり、これがいわゆる文字化けです。(エキスパートともなると、化けた文字列を見て元がわかるらしい)
では、代表的な日本語文字コードを紹介します。
- JIS(ISO-2022-JP)
RFC-1468で定義されていて、インターネットでは標準的な日本語文字コードです。電子メールではこの文字コードが利用されるていることが多いです(そのこと自体規格外なコトらしいですが)。
- シフトJIS
Microsoft社が決めたコードで MS-DOS や Windows や Mac などで使用されています。メモ帳やシンプルテキストで扱えます。
- EUC
Extended Unix Code の略で、UNIX で使われているコードです。インターネットの世界は UNIX を基礎としており、CGI を組んでいく上では避けて通れないコードです(最近はWin機も多いですが)。
- Unicode
ユニコード・コンソーシアムによって制定された文字コードです。Java や XML は、基本コードとして、Unicode を採用しており、最近の OS でも採用が進んでおり将来的にはスタンダードになるのではと言われています。
で、突然ですが、Perl で CGI を組む場合は EUC コードで記述するのが賢明です。
なぜかと言えば、Perl で文字列のマッチング処理や置換処理を行う際に、EUC 以外のコードでは厄介事が発生してしまうのです。原因は EUC 以外の文字コードには、perl が特別な意味として解釈してしまう文字が含まれているからです。EUC にはそのような文字がありません。したがって、スクリプトは EUC で記述するのがトラブル回避の第一条件となります。
ただし、配布用の CGI ではそうは行きません。世の中のユーザのほとんどは Windows であり Mac なのです。それらの OS は基本的にシフトJIS を標準文字コードとして利用しており、付属のテキストエディタもシフトJIS でしか処理できなかったりします。
そういう理由から、当サイトでは一部スクリプト以外は シフトJIS で組んであります(処理的にも面倒くさいことしてたりする…)。今の所、そのことによる問題というのは発生していないと思いますが、処理的には無駄な部分にも思えてたりもします。
最終的にスクリプトの文字コードを何にするかというのは別として、CGI を組む際に注意しておくべきなのは、文字コードを統一するということです。
CGI でブラウザから送られてくる文字情報に関して、文字コードを確定することは出来ません。CGI で受け取って文字コードを判別する手はありますが、受け取る際に何の文字コードで送られてくるかということはわかりません。ブラウザの挙動に依存しています。
従って、CGI で情報を受け取ったら、まず一意の文字コードに変換する必要があります。
Perl で文字コードを変換する際は jcode.pl というライブラリを使用します。使い方については、jcode.pl の私的な解説書が詳しいです。他そこら中の配布スクリプトで使われていると思いますので、ソースを覗けば具体例もいろいろと見つかると思います。
最近は Jcode.pm という Unicode 対応のモジュールも開発され、base64 エンコード(メールヘッダに日本語を使う場合に必要な処理)も簡単にできるなどなかなか便利そうですが、私もまだあまり使ったことがありません。公式サイトによると Perl5.8 より Perl 標準装備になるそうなので、文字コード変換のスタンダードになる日も近いみたいです。
ちなみに、UNIX では、古くから nkf という文字コード変換フィルタがありますが、プロバイダのサーバスペースやレンタルサーバのスペースなどでも、環境によって使えなかったりすることが多いので、配布スクリプトや UNIX ユーザ以外には jcode.pl の方がメジャーなようです。
スクリプトの文字コードは、スクリプト自身の文字コード、CGI で受け取る段階での文字コード、変数に格納されている状態での文字コード、出力する文字コードといくつかの状態を意識しないといけません。
例えば、
$str = "このTESTで充分";
$str =~ s/このTESTで充分/このテストで十分/;
print $str, "\n";
という処理があります(Perlメモより)。
$str =~ s/このTESTで充分/このテストで十分/;
print $str, "\n";
この処理が書かれたスクリプトの文字コードが JIS もしくは シフト JIS だとエラーが発生し、正常に実行できません。
シフトJIS で記述して、マッチ部分をエスケープして、
$str = "このTESTで充分";
$str =~ s/\QこのTESTで充分\E/このテストで十分/;
print $str, "\n";
としても、変換はできても文字化けになり、正常に実行できません。
$str =~ s/\QこのTESTで充分\E/このテストで十分/;
print $str, "\n";
もうひとつ、シフトJISで以下のような処理をしたとします(Perlメモより)。
if ($str =~ /\Q$keyword\E/) { print "マッチした\n"; }
この場合、 $keyword をエスケープしているので、一見上手くいきそうなのですが、そう簡単にはいきません。
$str = 'テスト'; のときに $keyword = 'X'; でパターンマッチを行なうとマッチしてしまうのです。なぜかというと、シフトJIS の「ス」の文字コードに「 X 」の文字コードが含まれているからです。細かくは解説しませんが、このようにアスキー文字のコードを含む日本語文字は組み合わせによってかなり多く、シフト JIS で書かれた上記マッチ判定処理はうまくいきません。
これらのような、JIS やシフト JIS で記述されることによって起こるマッチ処理や置換処理の不具合は、EUC コードで記述することで簡単に解決できます。
もしくは、マッチ処理や置換処理の際に毎度変数を EUC に変換して処理をするという手もないことはないのですが、面倒くさいです(doBOARD ではそれをやっていますが)。
ウィンドウズのメモ帳をテキストエディタにしていると、文字コードが複数あるということすら気にしないかもしれませんが、Perl スクリプトを記述する上では、日本語文字の処理の際にどうしても文字コードの問題が立ちはだかります。そんな時、まず第一にやるべきことは、スクリプトを EUC で記述する。CGI で受け取った情報は EUC に統一する。という2点です。
≫改行コードについて
改行コードとは、
「テキストファイル中で改行を意味する文字コードのこと。正確には、改行してカーソルを行頭に復帰する動作を指示するコードのこと。文字コード体系の種類には依存しないが、もともと「CR」(Carriage Return : 改行)と「LF」(Line Feed : 行頭復帰)の2つのコードが存在していたことから、WindowsではCR+LF、Mac OSではCR、UNIXではLFが使われている。Webブラウザや多くのテキストエディタはどの改行コードでも認識してファイルを読み込む(書き出す時は特に指定しない限りそれぞれのOS標準に従う)が、CGIスクリプトやプログラムのソースファイルなどは、改行コードをコンパイラ等が正確に認識せずエラーの原因となりやすい。」(e-Wordsより)
改行コードは OS によります。
改行コードについて意識し始めるのは、FTP による転送時だと思います。
文字コードの解説でも書きましたが、サーバに使われている OS は UNIX が多いのですが、クライアントマシンとしては Windows が圧倒的です。つまり、サーバとクライアントで OS が違うということ。それはつまり改行コードも違うということです。
通常、HTML などのファイルでは問題がないかもしれませんが、Perl スクリプトでは問題が起きます。
Windows で記述されたスクリプトでは改行が CR+LF になっていますが、UNIXサーバでは LF のみで改行コードとみなされ、余分な CR によってエラーとなります。
しかし、FFFTP などの FTP クライアントソフトでは、改行コードを自動的に設定して転送してくれたりするので、それほど意識していない人も多いかと思います。
しかし、Perl でスクリプトを記述する際には、改行コードを統一するという処理が必要不可欠となります。
CGI の種類にもよりますが、情報を受け取って処理し、保存したり、出力したりといった、例えば掲示板などの仕組みでも、改行コードの統一は不可欠です。
改行コードの統一には以下のコードを使います。
詳細は Perlメモで読んでいただけるとわかると思いますが、\n や \r というものは、Perl で論理的に定義された復帰文字と改行文字だからです。Perl の中では、OS によらず改行は実は \n だったりするのです。つまり、\nを出力した時のコードがOSによって異なるということです。
したがって、\r や \n といった論理的な文字で変換するのではなく、\x0D や \x0A という改行コード値を改行文字に変換するのが正しい、ということになります。
「テキストファイル中で改行を意味する文字コードのこと。正確には、改行してカーソルを行頭に復帰する動作を指示するコードのこと。文字コード体系の種類には依存しないが、もともと「CR」(Carriage Return : 改行)と「LF」(Line Feed : 行頭復帰)の2つのコードが存在していたことから、WindowsではCR+LF、Mac OSではCR、UNIXではLFが使われている。Webブラウザや多くのテキストエディタはどの改行コードでも認識してファイルを読み込む(書き出す時は特に指定しない限りそれぞれのOS標準に従う)が、CGIスクリプトやプログラムのソースファイルなどは、改行コードをコンパイラ等が正確に認識せずエラーの原因となりやすい。」(e-Wordsより)
| OS | 記号 | 改行文字 | 改行コード値(10進) |
|---|---|---|---|
| Windows(NT,MS-DOS含む) | CR+LF | \n | \x0D\x0A(1310) |
| UNIX | LF | \n | \x0A(10) |
| Macintosh | CR | \n | \x0D(13) |
改行コードについて意識し始めるのは、FTP による転送時だと思います。
文字コードの解説でも書きましたが、サーバに使われている OS は UNIX が多いのですが、クライアントマシンとしては Windows が圧倒的です。つまり、サーバとクライアントで OS が違うということ。それはつまり改行コードも違うということです。
通常、HTML などのファイルでは問題がないかもしれませんが、Perl スクリプトでは問題が起きます。
Windows で記述されたスクリプトでは改行が CR+LF になっていますが、UNIXサーバでは LF のみで改行コードとみなされ、余分な CR によってエラーとなります。
しかし、FFFTP などの FTP クライアントソフトでは、改行コードを自動的に設定して転送してくれたりするので、それほど意識していない人も多いかと思います。
しかし、Perl でスクリプトを記述する際には、改行コードを統一するという処理が必要不可欠となります。
CGI の種類にもよりますが、情報を受け取って処理し、保存したり、出力したりといった、例えば掲示板などの仕組みでも、改行コードの統一は不可欠です。
改行コードの統一には以下のコードを使います。
s/\x0D\x0A|\x0D|\x0A/\n/g;
よくある配布スクリプトでは、s/\r\n|\r/\n/g; のように記述していますが、この記述は厳密には正しくありません。
詳細は Perlメモで読んでいただけるとわかると思いますが、\n や \r というものは、Perl で論理的に定義された復帰文字と改行文字だからです。Perl の中では、OS によらず改行は実は \n だったりするのです。つまり、\nを出力した時のコードがOSによって異なるということです。
したがって、\r や \n といった論理的な文字で変換するのではなく、\x0D や \x0A という改行コード値を改行文字に変換するのが正しい、ということになります。
≫テキストエディタについて
Windows 付属のメモ帳ではシフトJIS のテキストファイルしか編集できません。しかし、ここまで述べてきたように文字のマッチ処理や置換処理だどを行う場合は、Perl スクリプトを EUC で記述するのが賢明です。そのためには EUC コードで編集の出来るテキストエディタが必要です。
また、文字コードと同じように、改行コードにも融通のきくテキストエディタだとさらに便利な気がします。
幸いなことに、そのような機能を持ったフリーのテキストエディタが存在します。以下にいくつか挙げておきますので、ご参考に。(*実際使ったわけではないので、使い勝手やバグなどのクレームはなしで。作者に伝えましょう。)
●Windows
また、文字コードと同じように、改行コードにも融通のきくテキストエディタだとさらに便利な気がします。
幸いなことに、そのような機能を持ったフリーのテキストエディタが存在します。以下にいくつか挙げておきますので、ご参考に。(*実際使ったわけではないので、使い勝手やバグなどのクレームはなしで。作者に伝えましょう。)
●Windows
- MKEditor
複数の文字コード・改行コードに対応。初心者にもわかりやすく、上級者の要望も満たす高機能が備わってます。私の場合、そして、このエディタの最大の特徴である「タブ」。複数のファイルを同時に開いてタブで切り替えながら編集することが可能です。かなりオススメです。 - 秀丸(シェア)
- TeraPad
- xyzzy
- サクラエディタ
- Emacs
- vi
- gedit
≫ちょっと裏技
Windowsの話ですが、Internet Explorer のソース表示を任意のテキストエディタに設定することができます。
Take's Modeのメモ帳トラッパーを使います。詳しくはダウンロードして ReadMe などに書いてあると思いますんで割愛しますが、便利なので挑戦してみましょう。簡単です。
だたし、Internet Explorer6.0 でメモ帳トラッパーを使用すると、起動のたびに「IEのバージョンは不明です」というダイアログが出てしまいます。
その現象を解消するツールはこちらで公開されています。Vectorはこちら。
参照:HTML, CGIでの文字コード指定についてもご覧願います。
だたし、Internet Explorer6.0 でメモ帳トラッパーを使用すると、起動のたびに「IEのバージョンは不明です」というダイアログが出てしまいます。
その現象を解消するツールはこちらで公開されています。Vectorはこちら。
参照:HTML, CGIでの文字コード指定についてもご覧願います。
TOP > スクリプト制作メモ > 文字コードと改行コードについて