YAPC::Asia::2008

すでに正解が書かれていますが、

[を] Unicode の16進数の実体参照を正規表現などで元に戻す
pack と Encode::decode を使うと良いみたい。
はてなブックマーク - miyagawaのブックマーク / 2008年05月11日
それ HTML::Entities::decode / regexp でも chr(hex($1)) のほうがわかりやすくないかな

繰り返しておくだけの価値はあるので。

HTML::Entitiesを使う

まず、HTML::Entitiesdecode_entities()を使うという方法があります。これがベストプラクティスかな。

#!/usr/local/bin/perl
use strict;
use warnings;
use Encode;
use HTML::Entities;

my $eucjp = "Dan Kogai \xbe\xae\xbb\xf4\xc3\xc6 断固害";
my $utf8  = decode('eucjp', $eucjp);

binmode STDOUT, ':utf8';
print $utf8, "\n";
print decode_entities($utf8), "\n";

注意点としては、先にUTF-8にしておくということが挙げられます。これならUTF-8にした時点で、文字参照(character reference)の部分は(ASCIIなので)そのままなので。その逆だと、decode_entities()でUTF-8化された部分と元の文字コードの入り交じったバイト列が出来てしまいます。

Dan the Perl Monger

正規表現でやる

どうしても正規表現でやりたい、という場合はこんな感じでしょうか。

#!/usr/local/bin/perl
use strict;
use warnings;
use Encode;

my $eucjp = "Dan Kogai \xbe\xae\xbb\xf4\xc3\xc6 断固害";
my $utf8  = decode('eucjp', $eucjp);

binmode STDOUT, ':utf8';
print $utf8, "\n";
$utf8 =~ s/&#x([0-9A-Fa-f]{2,6});/chr hex $1/eg;
print $utf8, "\n";

ただし、この場合には&のように名前で参照されるものが残ってしまいます。なるべくHTML::Entitiesをつかった方がよいでしょう。

Dan the Man with Too Many Bits and Bytes to Transcode