Data::Dumper や Smart::Comments の出力を utf8 文字列に変更する



Perl で開発する時は、Data::Dumper や Smart::Comments が便利だ。

Data::Dumper を使う場合

use strict;
use warnings;
use Data::Dumper;

my @arr = (
	'this value',
	'that value',
);
warn Dumper(\@arr);

出力

$VAR1 = [
          'this value',
          'that value'
        ];

Smart::Comments を使う場合

use strict;
use warnings;
use Smart::Comments;

my @arr = (
	'this value',
	'that value',
);
### @arr

出力

### @arr: [
###         'this value',
###         'that value'
###       ]

日本語データを扱う時の問題

所が、プログラムが日本語データを扱っている場合は、標準エラーに encoding を指定しても、これらのモジュールからの出力は当該文字の Unicode文字番号(16進数)に変換されてしまう。

Data::Dumper からのエラー出力

use strict;
use warnings;
use utf8;
use Data::Dumper;

binmode STDERR, ':encoding(utf8)'; #この指定は、自分で指定したエラーメッセージになら期待通り。

warn "日本語エラーメッセージ。\n";

my @arr = qw(
	こんな値や
	あんな値
);
warn Dumper(\@arr);

出力

日本語エラーメッセージ。
$VAR1 = [
          "\x{3053}\x{3093}\x{306a}\x{5024}\x{3084}",
          "\x{3042}\x{3093}\x{306a}\x{5024}"
        ];

Data::Dumper からのエラー出力の日本語化

長らくこれはやむを得ない事として甘んじていたのだけど、この間 __WARN__ フックを利用する解決法を思いついた。

use strict;
use warnings;
use utf8;
use Data::Dumper;

binmode STDERR, ':encoding(utf8)';

# 標準エラーへの出力を UTF-8 文字列にする
local $SIG{__WARN__} = sub {
	warn join("",
		map {
			my $str = $_;
			$str =~ s/\\x\{(\w{4})\}/pack('U', hex($1))/eg; # \x{abcd} -> 文字
			$str;
		} @_
	);
};

my @arr = qw(
	こんな値や
	あんな値
);
warn Dumper(\@arr);

出力

$VAR1 = [
          "こんな値や",
          "あんな値"
        ];

Smart::Comments も、内部的には Data::Dumper を使っているので同じ。

るんたるんた♪