Perl5 においてファイルからの読取る場合における Malformed UTF-8 問題
Perl::Critic が最近 PerlIO layer に :utf8 つかうと怒ってくるけど、べらんめえしったことか! とおもっていたら、サイトが表示できなくなった(このような問題を hasegawayosuke 現象と我々はよんでいる)ので、ちゃんと調べた。
https://metacpan.org/module/Perl::Critic::Policy::InputOutput::RequireEncodingWithUTF8Layer
以下のようなスクリプトを実行する。
#!/usr/bin/perl use strict; use warnings; use utf8; use 5.010000; use autodie ':all'; use Devel::Peek; { open my $ofh, '>', 'foo.txt'; print $ofh "\xC0\xAF"; } for my $layer ('<:utf8', '<:encoding(utf8)', '<:encoding(utf-8)') { print "---- $layer\n"; open my $fh, $layer, 'foo.txt'; my $src = do { local $/; <$fh> }; print "SRC: '$src'\n"; Dump($src); print "\n\n-------\n"; }
以下のような結果をえる。
---- <:utf8 utf8 "\xC0" does not map to Unicode at charset.pl line 17, <$_[...]> chunk 1. SRC: '/' SV = PV(0x84ff0d0) at 0x8764768 REFCNT = 1 FLAGS = (PADMY,POK,pPOK,UTF8) PV = 0x8754358 "\300\257"\0Malformed UTF-8 character (2 bytes, need 1, after start byte 0xc0) in subroutine entry at charset.pl line 19, <$_[...]> line 1. [UTF8 "\x{0}"] CUR = 2 LEN = 12 ------- ---- <:encoding(utf8) utf8 "\xC0" does not map to Unicode at charset.pl line 17. utf8 "\xAF" does not map to Unicode at charset.pl line 17. SRC: '\xC0\xAF' SV = PV(0x84ff0d0) at 0x8764768 REFCNT = 1 FLAGS = (PADMY,POK,pPOK,UTF8) PV = 0x8754358 "\\xC0\\xAF"\0 [UTF8 "\\xC0\\xAF"] CUR = 8 LEN = 12 ------- ---- <:encoding(utf-8) utf8 "\xC0" does not map to Unicode at charset.pl line 17. utf8 "\xAF" does not map to Unicode at charset.pl line 17. SRC: '\xC0\xAF' SV = PV(0x84ff0d0) at 0x8764768 REFCNT = 1 FLAGS = (PADMY,POK,pPOK,UTF8) PV = 0x8754358 "\\xC0\\xAF"\0 [UTF8 "\\xC0\\xAF"] CUR = 8 LEN = 12 -------
ここで、:encoding(utf8) は utf-8 のことだが :encoding(utf-8) は utf-8-strict をつかうので、よりベターである。
【考察】
":encoding(utf-8)" を素直につかえばいいが、無駄にながいのでどうにかしてほしい。また、Perl::Critic のアドバイスは素直にきくことによって人生をおだやかにすごすことができる。特に自称中級者にかぎってアドバイスを無視する傾向があるので気をつけていきたい。
【参考文献】
- http://www.perlmonks.org/?node_id=644786
- http://blog.livedoor.jp/xaicron/archives/50927806.html
- http://blog.livedoor.jp/dankogai/archives/51290188.html
【追記】
nihen【:encoding(utf8) は utf-8 のことだが】は間違い。もともとutf8はliberal http://search.cpan.org/~dankogai/Encode-2.44/Encode.pm#UTF-8_vs._utf8_vs._UTF82011/11/02
だそうです!