MySQL-5.5上に載せてあるデータベースのキャラクタセットで4バイトのunicodeが使える様になったので、調子に乗って、これまでに作ったCGIのページ出力も、EUC-JPからUTF-8に切り替える作業を進めている。
で、うちのサイトでgoogleクローラが最も熱心に拾って行く「今日は何の日?」も去る12月21日(水)に出力キャラクタセットをEUC-JPからUTF8に切り替えた。
昨日ふと見ると、明治5年以前の出来事では和暦の年月日を表示しているのだが、その「xx月」の部分が消えていた。
どうも、PerlでUTF-8を使う際の作法を守らず、ソースコードをUTF-8に変換して、HTMLのMETAタグのキャラクタセット指定をutf-8に変更、 use utf8 行とデータベースから受けた変数に対するutf8::decode行を追加しただけの手抜き対応をしたのが
手抜きすると、やっぱりどこかでボロが出るなぁと思いつつ、こちらのサイトを参考に、Perl上でUTF8を使う際の作法を整理して、プログラムを修正した。
ちなみに、使用しているPerlは、Ver.5.8.8 と、Ver.5.12.4 である。
Perlのutf8フラグを意識して、一通り、utf8::encode(utf8フラグOff)、utf8::decode(utf8フラグOn)、no utf8 行で体裁を整えたのだが、状況は改善しなかった。
仕方が無いので、テストプログラムを組んで試してみた処、次の様な結果になった。ソースコードはUTF-8で記述している。
サンプル1
ソースコード
#!/usr/bin/perl
use utf8;
my($string) = '12';
binmode STDOUT => ":utf8";
if($string eq '1u'){
print "閏1月\n";
}else{
print "$string月\n";
}
print length($string), "\n";
実行結果
2
サンプル2
ソースコード
#!/usr/bin/perl
use utf8;
my($string) = '12';
binmode STDOUT => ":utf8";
if($string eq '1u'){
print "閏1月\n";
}else{
print "$string"; # ←Latin-1の文字列が入る変数直後でprint文を分離
print "月\n";
}
print length($string), "\n";
実行結果
12月
2
以上の結果で推測されるのは、Latin-1(UTF-8でもあるハズ)の“12”と、UTF-8の“月”が、誤った1文字として処理されてしまっているようだ、ということである。
正直な感想として、この様なものに起因する「文字化け」は、原因に
先の記事にもあったが、正に
スクリプト内に8bitのバイト列がある(たとえば、文字列リテラルに、Latin-1がある)なら、 "use utf8" は、不幸をもたらすでしょう。バイト列は、ほとんどの場合、適切なUTF-8ではないからです。を地で行っている感じである。
こんな訳で、
UTF-8は文書の記述に便利な反面、プログラムを組む際には注意が必要だと、改めて感じた次第である。
(追記)
同様の不具合を回避する方法として、もっとスマートなものは無いだろうかと考えてみたのだが、 print 文は no utf8 を宣言したスコープ内で実行するしかない様な気がする。折角UTF-8でソースを書いて、UTF-8で入出力しようとしても、プログラム中で出力部分は no utf8 では、ちょっと残念な感じが否めない。
なんとかならないものだろうか。








コメントする