ええ加減散髪に行ってきた。
これでもかってぐらい切ってもらった。
同じ値段でやってもらうのが申し訳ないぐらい切ってもらった。
まぁ先延ばししてきて髪の毛がすごい伸びてやっと散髪にいくというのはひどいですが、
しかしすっきりしたのでこれでよしとしましょう。
そういえば今日はエイプリルフールか。冗談を言う日ではあるけれど、
しかしそんな日になにやら真面目に発表するところもあるわけだしね。
だからエイプリルフールに便乗した行動は、必ずしも冗談じゃないのだよというのは最近思うところですね。
URLで使える文字はRFC3986によれば数字・アルファベット・ハイフン・ピリオド・アンダースコア・チルダらしい。
これ以外の文字は%E5などして表示する必要があると。
PHP使ってるとこの辺は自動的に考えてくれるので、あまり気にしなくていい。
ただ受け取った文字列のエンコーディングはわからないので、内部で使ってるエンコーディングに統一する必要があるが。
しかし受け取るのもUTF-8、使うのもUTF-8なら気にすることはないでしょう。
作るのはurlencode関数でできるそうだ。
Perlでこれをやるには正規表現で置換するのが普通ですね。
my $x='%83R%83%93%83Z%83%93%83g%82%a9%82%e7%89%ce%82%aa%95%ac%82%a2%82%bd';
$x=~s/%([0-9A-Fa-f]{2})/pack('C',hex($1))/eg;
print $x;
ここではuse utf8;の類はしないで、Shift_JISで出力すれば端末で見れることを考える。
有名な方法ですね。
ただ以前pack(‘C’,hex($1))はかなり無駄に見えるからchr(hex($1))と書く方がよいのではというのを見たことがある。
僕もそれには賛成ですね。というわけで以下はそんな風に書きます。
まぁPerlでCGI作るわけでもないのでこれだけなら記事にすることではないのだが、
ただこれが思惑通り行かないこともあるんですね。
それがuse utf8;の類を使ったときですね。
use encoding 'shiftjis';
use Encode;
binmode(STDOUT,':encoding(shiftjis)');
my $x='%e3%83%9e%e3%83%b3%e3%83%9b%e3%83%bc%e3%83%ab%e3%81%8c%e5%90%b9%e3%81%a3%e9%a3%9b%e3%82%93%e3%81%a0';
$x=~s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
print decode('utf8',$x);
use encoding ‘shiftjis’;とエンコーディングがShift_JISであると示す。
そうすると急にうまく行かなくなる。
use utf8;なら問題なくいくことも多いけど、まぁたまにうまくいかないときもある。
実はそうもプログラムは間違ってないんですよ。
このあたりがuse utf8;の難しいところです。
use utf8;の類を宣言すると普通は文字列にUTF-8フラグというのが立つ。
これは文字をUnicodeで表しておくするモードですね。
print ord(‘田’);としたとき、Shift_JISの環境ならば普通は147と出てくる。
というのも’田’は0x93と0x39の2バイトで表される。その1バイト目は0x93、10進数に直すと147となるわけだ。
しかしuse utf8;の類をすると、この結果は30000となる。
このときは田というのは0x7350と記録されているわけだ。その1文字目の0x7350を10進数に直すと30000と。
その違いがかなり厄介なんですね。
というのはこの置換のとき、%e3というのを発見したら、chr(hex(‘e3’))に置き換えるわけだが、
これが厄介で、use utf8;してるとUnicodeの0xE3に置き換えてしまう。
UTF-8フラグ自体はこうやったら外せるんですね。
$x=encode('utf8',$x);
しかしこれで外したところで状況が改善されるわけでもない。
一体どうなっているのだろうか。
やはりこういうことはUTF-8フラグをつけないのがよいのだろうか。
use strict;
use warnings;
use encoding 'shiftjis';
use Encode;
binmode(STDOUT,':encoding(shiftjis)');
my $x;
{
no encoding 'shiftjis';
$x='%e3%83%9e%e3%83%b3%e3%83%9b%e3%83%bc%e3%83%ab%e3%81%8c%e5%90%b9%e3%81%a3%e9%a3%9b%e3%82%93%e3%81%a0';
$x=~s/%([0-9A-Fa-f]{2})/pack('C',hex($1))/eg;
}
print decode('utf8',$x);
とりあえずこうすればうまくいくようになった。
しかしどうしたものかな。全部Unicodeというのも困ったものだ。