マルチバイトを知ったperlは便利

perl 5.8からマルチバイト文字列への対応がすばらしくなりました。
これは日本語を使う人にとってはありがたい話だ。
書いてる途中でなんか飛んでしまったけど、気を取り直して書きますか。
と、その前に、マッチについてのメモ。

while($line=){
if( $line=~ m/^(.+)\s+([0-9])\s*$/ ){
print "$1 : $2\n";
}
}

このようにマッチした結果の()の内容はそれぞれ、$1,$2…に入ると、そういうことです。
これを知らなかったのは非常に残念。活用していきたいものだ。
あと、複数マッチという機能もあるのだが、これはこの先で。


さて、UTF-8を内部エンコーディングに使うメリットは何よりその冗長性でしょう。
UTF-8の構造はとんでもなくリッチ。w:ja:UTF-8のエンコード体系を見ればよくわかるかと。
EUC-JPはASCII範囲内は8ビット目は0、範囲外はすべて1、けどそれだけの区別。
田中はEUC-JPではC5 C4 C3 E6というビット列だが、租鎮罅という文字列はC1 C5 C4 C3 E6 A1と、一見田中を含んでるように見えてしまう。
Shift_JISはさらに悲惨だけどな。
しかしUTF-8は、1ビット目の範囲と2ビット目以降の範囲は重ならない。なので文字の範囲がずれてしまうことは絶対にない。
だからこそデータ量がとんでもないことになるんだけど。ほとんどの文字が3ビットなのはそこにあるといっても間違えじゃないでしょう。
さて、このメリットを利用することはマッチとかで有用ですよ。

#!/usr/bin/perl
use utf8; #use encoding "euc-jp";
open(IF,"<:encoding(shiftjis)","./test.txt");
binmode(STDOUT, ":utf8");
while(){$data.=$_;}
%datas = $data=~m/([ぁ-ん]+)\s+([0-9]+)\s*/gm;
while( ($name,$value) = each(%datas) ){
print "$name : $value\n";
}

まず、use utf8;と書く。これはUTF-8でソースコードが書かれている印。
これを付けることでマルチバイト文字列関係のサポートがよくなる。
もしeuc-jpとかだったら、use encoding “euc-jp”;と書けばいい。ここからもわかるけどUTF-8は特別扱いです。
openは見慣れないかも知れないけど、3引数open、モードとファイル名を分けて書くと。
そのモードのところに:utf8か:encoding(shiftjis)などでエンコーディングを示す。ここもUTF-8だけ特別扱い。
ここで、STDIN・STDOUTを使うときはbinmodeでエンコーディングを後付けしないといけない。
実は普通にopenした後に、binmodeで後付してもOKです。まぁどっちにしてもエンコーディングは示そうと言うことです。
じゃないと「Wide character in print at…」と言われてしまう。
それで後はあまり変わらない。文字列を連結して、マッチさせてと。
ここで、複数マッチを使ってる。gオプションがそれ。mは改行コードの取り扱いのオプション。
それで()がないときはマッチしたの全部の配列を作ってくれる、()があるときは()の中身を順に取り出したのを並べた配列を作ってくれる。
だから、

すずめ 100
うさぎ 200

をやったときは()がなければ(‘すずめ 100′,’うさぎ 200’)の配列が、()があるときは(‘すずめ’,’100′,’うさぎ’,’200′)の配列が作成される。
ところが連想配列に入れている。
けど連想配列の初期化の方法は(‘キー1′,’値1′,’キー2′,’値2’)とする方法もある、(‘キー1’=>’値1′,’キー2’=>’値2’)の方が直感的だが。
そこからもだいたい理解できると思う。
それで連想配列をeachで1つ1つ取り出して、print、これで完了。
今回は出てこなかったけど、UTF-8基準でエンコード・デコードするencodeとdecodeがある。
今回はopen時にエンコーディングを指定したけど、STDIN,STDOUT以外は別にしなくてもエラー出ません。
ただ、そのとき変換が必要だから、encode,decodeを使うわけ。

use Encode;
use Encode::Guess qw/euc-jp shiftjis 7bit-jis/;
while(){
$data = Encode::decode('Guess',$_);
print OF Encode::encode('shiftjis',$data);
}

しかしせっかく指定しておけば自動変換できるんだから、まぁそれでいいと思う。
Guessは類推でやってくれるということ。


東アジアの人間からすれば、非常にありがたいことですね。
拡張から、本体に取り込まれていくというのは非常にありがたいことです。
いままでjcode.pmだったかな。
けど用意めんどくさいしね。どこにでもある安心というのはありますよね。
で、なぜこんなことが必要だったかは後に説明したいと思います。
文字コードとめんどくさいことになってしまったのさ。
そうそう、set utf8;などを付けなければ、いままでとあまり扱いは変わらないので、その点は安心。