文字コードのあれこれ

あれこれって言っても入力と出力の所について。
文字コード変換はこちら


Perlの俺ルール - 足跡」で入力と出力の部分についての俺ルールを書きましたが、やはり独りよがりな俺ルールでした。
UTF8文字列での正しい入出力処理はこちら:
404 Blog Not Found:#perl - utf8::decode()ではなくEncode::decode_utf8()を使うべき理由
つまり「外部から入力されたUTF8文字列に対してはEncode::decode_utf8()を使うべし」ということ。
理由としては上記リンク先にも書かれていますが、不正なUTF8文字を無害な文字へと変換する機能が「utf8::decode()」には無いのに対し「Encode::decode_utf8()」には備わっている事が挙げられます。
これによってより簡単な記述でセキュアなスクリプトになります。
要は外部入力を内部表現に変換するのにはEncode使えということだそうです。


使い方例:

use strict;
use warnings;
use utf8;
use Encode;

&main();

sub getdata{
    # 外部からデータを取得するルーチン。戻り値は文字列。
}

sub main{
    my $data = getdata();
    my $text = Encode::decode_utf8($data);

    # $textに対する何かの処理。

    utf8::encode($text);
    print $text;
}

ただし上記コードが期待通りに動作するのはEncodeモジュールのバージョンが2.13以上での話だそうで。
Encodeのバージョンが2.12以下の環境で上記コードを実行すると、$dataに既にutf8フラグが立っている時にエラーを起こします。
なのでEncodeのバージョンに依らないようにするには以下のような感じ。

use strict;
use warnings;
use utf8;
use Encode;

&main();

sub getdata{
    # 外部から文字列データ取得
}

sub main{
    my $data = getdata();
    my $text = Encode::is_utf8($data) ? $data : Encode::decode_utf8($data);

    # $textに対する処理。

    utf8::encode($text);
    print $text;
}

入力に使われる文字列のエンコーディングがutf8以外の場合は、Encode::decode()を使うと良い。
その場合は下記のような感じ。

use strict;
use warnings;
use utf8;
use Encode;

&main();

sub getdata{
    # 外部から文字列データ取得
}

sub main{
    my $data = getdata();
    my $encoding = 'euc-jp';
    my $text = Encode::is_utf8($data) ? $data : Encode::decode($encoding, $data);

    # $text に対する処理

    utf8::encode($text);
    print $text;
}

Encode::decode使ってるのが一番平和な気がしないでもない。