駄目です。
[を] Perl の utf8 まわりのおまじない最近良く使うおまじない、というかイディオム。utf8::decode($text) unless utf8::is_utf8($text);
こういう場合は、Encode::decode_utf8()
でないと。
以下をごらんください。
#!/usr/bin/perl use strict; use warnings; use Encode; use Devel::Peek; for my $bytes ( "\x2F", "\xC0\xAF", "\xE0\x80\xAF", "\xF0\x80\x80\xAF" ) { my $utf8 = $bytes; utf8::decode($utf8) unless utf8::is_utf8($utf8); Dump($utf8); }
から持ってきた例題ですが、見ての通り、utf8::decode()
は、不正なUTF-8バイト列に対して何もしません。
今度はEncode::decode_utf8()
を見てみましょう。
#!/usr/bin/perl use strict; use warnings; use Encode; use Devel::Peek; for my $bytes ( "\x2F", "\xC0\xAF", "\xE0\x80\xAF", "\xF0\x80\x80\xAF" ) { my $utf8 = decode_utf8 $bytes; Dump($utf8); }
今度は不正な文字は、全て\x{fffd}
、REPLACEMENT CHARACTERに置き換えられています。
Validationの観点だけではなく、簡潔性の観点からも、Encode::decode_utf8()
はおすすめです。すでに UTF-8 flag がついた文字列はそのままコピーするだけなので、条件分岐も不要です。
#!/usr/bin/perl use strict; use warnings; use Encode; use Devel::Peek; { use bytes; my $bytes = '小飼弾'; Dump($bytes); my $utf8 = decode_utf8($bytes); Dump($utf8); } { use utf8; my $bytes = '小飼弾'; Dump($bytes); my $utf8 = decode_utf8($bytes); Dump($utf8); }
utf8.pm
のPODにもこうあります。
$success = utf8::decode($string)Attempts to convert in-place the octet sequence in UTF-X to the corresponding character sequence. The UTF-8 flag is turned on only if the source string contains multiple-byte UTF-X characters. If $string is invalid as UTF-X, returns false; otherwise returns true.
Note that this function does not handle arbitrary encodings. Therefore Encode is recommended for the general purposes; see also Encode.
utf8::decode()
は、定数文字列、すなわちソース内の文字列に限って利用すべきでしょう。外部入力はEncode
に振りましょう。
Dan the Encode Maintainer
弾さん書くしかないでしょう。