2006 年 3 月 16 日 23 時 52 分

ファイルハンドルへの組み込み


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


文字コード変換をファイルハンドルに組み込んでみよう。

ファイルハンドルクラスには、
変換を行いながら出力を行うことになるので、
最低限 3 つの引数が必要だ。

・実際の出力先ファイルハンドル
・入力の文字コード
・出力の文字コード

引数は、連想配列(ハッシュ)を使って渡すことにしよう。
プログラムの見た目がすっきりするからだ。
使い手が以下のように呼び出せるように作ってみよう。

tie *OUT, 'EncoderHandle',
    'IF_ENCODING' => 'euc-jp',
    'IO_ENCODING' => 'shift_jis',
    'HANDLE' => *STDOUT;

IF_ENCODING はプログラムの文字コード、
IO_ENCODING は、変換後の文字コード、
HANDLE は、実際にデータを書き出すファイルハンドルだ。


# 独自クラス。
package EncoderHandle;

# 今日は Encode を使う
use Encode;

# Tie::Handle を継承。
use Tie::Handle;
our @ISA = ('Tie::Handle');

# tie 関数に対応してオブジェクトを作成する。
# パラメータのチェックなどは省略。
sub TIEHANDLE {
    my $package = shift;
    my %param = @_;
    bless(\%param, $package);
}

# 書き出し系関数のハンドラ。 引数は順に、
# インスタンス自身、データ、長さ、
# そして省略可能な、データ内の書き出し開始位置だ。
sub WRITE {

    # 分かりやすいように引数を変数に格納。
    my $this   = $_[0];
    my $length = $_[2];
    my $offset = ($_[3] or 0);
    my $text = substr($_[1], $offset, $length);
    my $handle = $this->{'HANDLE'};
    my $if_enc = $this->{'IF_ENCODING'};
    my $io_enc = $this->{'IO_ENCODING'};

    # コード変換。
    my $length = Encode::from_to($text, $if_enc, $io_enc);

    # 失敗すれば死ぬ。
    die "Can't convert encoding" if not defined $length;

    # 変換したデータを書き出す
    print $handle $text;
}

# メインのパッケージに戻る。
package main;

# tie を呼び出して、OUT に割り付ける。
tie *OUT, 'EncoderHandle',
    'IF_ENCODING' => 'euc-jp',
    'IO_ENCODING' => 'shift_jis',
    'HANDLE' => *STDOUT;

# print, printf などのために選択しておく。
select(OUT);

print 'Print', 'Some', 'String', "\n";
printf "%s=%d\n", 'Value', 1234;
syswrite OUT, 'syswrite!', 9;



Copyright (c) 1994-2007 Project Loafer. All rights reserved.