2008年04月09日 01:00 [Edit]

perl - Encode 入門

camel

すでにOSCONでもYAPCでも、あちこちそちこちでこの基本方針に関しては話したのですが、ここ 404 Blog Not Found でも改めて。

Perl で utf8 化けしたときにどうしたらいいか - TokuLog 改め だまってコードを書けよハゲ
入り口で decode して、内部ではすべて flagged utf8 で扱い、出口で encode する。これがすべてです!とにかくこの基本方針をまもっていれば幸せになれます。

ここでは、EUC-JPでエンコードされたファイル中の「小飼弾」「こがいだん」「コガイダン」「Kogai Dan」を正規表現で書き換えて標準出力にEUC-JPで出力するプログラムを例にとって説明します。

decode() then encode()

まず、こちらが基本中の基本。

use strict;
use utf8;
use Encode;
for my $argv (@ARGV){
    open my $fh, "<", $argv or die "$argv : $!";
    while(<$fh>){
        my $utf8 = decode("eucjp", $_);
        $utf8 =~ s{ (?:小飼|こがい|コガイ|Kogai)
                    [\s\x{3000}]* # \s + FULLWIDTH SPACE
                    (?:弾|だん|ダン|Dan)
                  }{Encode Maintainer}gmsx;        
        print encode("eucjp", $utf8);
    }
}

find_encoding()

くりかえしdecode()encode()する場合には、OOインターフェースを使った方が高速です。なぜなら(de|en)codeが文字コード名を解決する手間がなくなるからです。

use strict;
use utf8;
use Encode;
my $eucjp = find_encoding('eucjp');
for my $argv (@ARGV){
    open my $fh, "<", $argv or die "$argv : $!";
    while(<$fh>){
        my $utf8 = $eucjp->decode($_);
        $utf8 =~ s{ (?:小飼|こがい|コガイ|Kogai)
                    [\s\x{3000}]* # \s + FULLWIDTH SPACE
                    (?:弾|だん|ダン|Dan)
                  }{Encode Maintainer}gmsx;        
        print $eucjp->encode($utf8);
    }
}

PerlIO and open()

ファイルをopen()する段階で、文字コードを指定することもできます。以下の例では、入力の際にdecodeを済ませています。

use strict;
use utf8;
use Encode;
for my $argv (@ARGV){
    open my $fh, "<:encoding(eucjp)", $argv or die "$argv : $!";
    while(<$fh>){
        s{ (?:小飼|こがい|コガイ|Kogai)
           [\s\x{3000}]* # \s + FULLWIDTH SPACE
           (?:弾|だん|ダン|Dan)
        }{空気嫁}gmsx;        
        print encode("eucjp", $_);
    }
}

binmode()

さらにbinmodeを使うと、すでに開いているファイルハンドルの文字コードを変更することも可能です。use Encode;しなくても動いている点に留意してください。

use strict;
use utf8;
# use Encode;
binmode STDOUT, ":encoding(eucjp)";
for my $argv (@ARGV){
    open my $fh, "<:encoding(eucjp)", $argv or die "$argv : $!";
    while(<$fh>){
        s{ (?:小飼|こがい|コガイ|Kogai)
           [\s\x{3000}]* # \s + FULLWIDTH SPACE
           (?:弾|だん|ダン|Dan)
        }{404 Replacement Not Found}gmsx;        
        print;
    }
}

まとめ

Encodeには他にもうんざりするほどいろいろな機能がありますが、上記の基本で日常業務の9割5分はカヴァーされているかと思います。「decodeしていじってencode」、この基本をお忘れなく。

Dan the Encode Maintainer

See Also:


この記事へのトラックバックURL

この記事へのトラックバック
404 Blog Not Found:perl - Encode 入門
404 Blog Not Found:perl - Encode 入門【】at 2012年01月24日 22:14
良記事。 第7回■文字エンコーディングが生み出すぜい弱性を知る:ITpro だけど、問題点のみ具体例があって、対策にないのが片手落ちに感じられたので、その点を補足。
perl - EncodeでXSSを防ぐ【404 Blog Not Found】at 2009年03月03日 18:59
何年も前から使っている自分フレームワーク(というか自分モジュール集?)があるのだ...
最近Perlスクリプトを書いていて愕然とすること【日曜プログラマのそゞろ事】at 2008年07月24日 00:20
以前書いた 404 Blog Not Found:perl - Encode 入門 は大好評でしたが、 ウェブで利用される文字コード、UnicodeがASCIIを上回る--グーグルが明らかに:マーケティング - CNET JapanUnicodeがASCIIを追い越し、World Wide Web上で最も多く利用されている文字コー...
perl - Encode 中級【404 Blog Not Found】at 2008年05月08日 04:10
この記事へのコメント
keitaさん>そうだった、"deprecated"=「非推奨」。忘れてました。
nilさん>OK把握。

お目汚し失礼しました…… (to 弾さん&閲覧者各位)
Posted by Yuichirou at 2008年04月11日 18:33
たとえば
http://www.kt.rim.or.jp/~kbk/zakkicho/zakkicho16.html#D20061003-1
Posted by nil at 2008年04月10日 14:59
この場合、depricate は「非推奨」のほうの意味では?
Posted by keita at 2008年04月10日 08:44
> use encoding はどちらかというと deprecate したいプラグマなので。
へぇ……なぜ deprecate(非難する、反対する)するのか気になりますが、だとすれば、やはりソース中の文字列も decode 関数に通す、つまり基本同様「decodeしていじってencode」とすべきなのですね。
Posted by Yuichirou at 2008年04月09日 21:15
H.Iさん、
念のために、というよりperlioがstackableであることを示すために:を追加しました。
Yuichirouさん、
use encoding はどちらかというと deprecate したいプラグマなので。
Dan the Perl Monger
Posted by at 2008年04月09日 20:53
コード中にUTF8以外の文字コード(ex. EUC-JP)で文字列を書くときの
use encoding "EUC-JP"; # use utf8; の代わりに
も紹介しておくと良いかと。
Posted by Yuichirou at 2008年04月09日 18:22
と、思ったら少なくとも5.10では:encoding()でもencoding()でも動きますね…いつからだろう?
Posted by H.I. at 2008年04月09日 15:29
encodingに「:」が足りません…
Posted by H.I. at 2008年04月09日 08:45