2009年09月13日 13:00 [Edit]

#perl - utf8::decode()ではなくEncode::decode_utf8()を使うべき理由

camel

駄目です。

[を] 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にもこうあります。

perldoc utf8
$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


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

この記事へのトラックバック
Perl Cookbook (English, Kindle Ed.) Christiansen / Torkington [邦訳: Perlクックブック] というわけで解説。 2013/03/04:Unicode::UTF8 がガチ爆速すぎる - bayashi.net encode より decode のが差が大きい感 ...
perl - 最速のUTF-8処理法【404 Blog Not Found】at 2013年03月04日 23:32
Perl の CGI.pmはよくお世話になりますが、UTF8を扱おうとすると、utf8フラグがたったり、なかったりと問題があるようで、めんどくさいのでCGI.pmでパラメータ受け取るときにすべてのパラメ??.
CGI.pmをUTF8対応にする【蜘蛛の糸をつむぐには...】at 2009年09月17日 02:02
404 Blog Not Found:#perl - utf8::decode()ではなくEncode::decode_utf8()を使うべき理由 Validationの観点だけではなく、簡潔性の観点からも、Encode::decode_utf8()はおすすめです。すでに UTF-8 flag がついた文字列はそのままコピーするだけなので、条件分岐も不要です
[perl]Encode::decode_utf8()であってもis_utf8()を使うべき理由【それ、Gentooだとどうなる?】at 2009年09月14日 20:37
この記事へのコメント
こういうことをきちんと解説した本がないから、みんなが自己流・試行錯誤でプログラムを書いて、結果としてPerlの評判を落としてしまう。
弾さん書くしかないでしょう。
Posted by 挧 at 2009年09月15日 22:27
「<p>こういう場合は、<code>Encode::decode_utf8()でないと」の部分、「</code>」が抜けているので、その後ろが全部等幅フォントになってしまっています。
Posted by Passer-by at 2009年09月14日 10:51
> すでに UTF-8 flag がついた文字列はそのままコピーするだけなので、条件分岐も不要です。

これは知りませんでした。
Posted by xaicron at 2009年09月13日 16:54