[kansaipm] Re: Perl 5.6 ネタ

mishima at momo.so-net.ne.jp mishima at momo.so-net.ne.jp
Thu Apr 6 20:03:06 CDT 2000


三嶋です。

岡部さんこんにちは。
おかげさまで perl-win32-j のほうではいつも勉強させていただいてます。

早速、というか遅ればせながら、Filter モジュールを入れて、わたなべさん
の SJIS.pm もパクらせていただきました。
さらに、ファイルI/O時にフィルタを仕込めるようにした FileHandle のサブ
クラスを作ってみましたので、後ろにサンプルプログラムと共に付けておきま
す。(FileFilterと名づけました)

#ソースにコメントがなくて申し訳ないのですが、興味のあるかたは解読してみ
#てください。

サンプルでは、おおよそこんな感じで使っています。
$in  = new FileFilter("<&STDIN",  sub{ SJISをUTF8に変換する処理 });
$out = new FileFilter(">&STDOUT", sub{ UTF8をSJISに変換する処理 });
$out->autoflush(1);		# スーパークラスのメソッド
while($_=$in->readline){	# 読込み時に SJIS->UTF8
    $out->printf(...);		# 書込み時に UTF8->SJIS
    $out->print(...);		# 書込み時に UTF8->SJIS
}

サンプルの実行例は、以下の通りです。
最初に1行のメッセージが出ます(「表」の字を無理に使ってます^^)。プロ
ンプト '> ' の後に適当な文字列を入力すると、文字コードの判定と文字数お
よびバイト数が表示され、次の行に正規表現の \b と \B にマッチする箇所に 
| と - を挿入した結果が表示されます。

bash-2.02$ test.pl
単語の境界に"|"を、それ以外の文字境界に"-"を挿入して表示します。
> 日本語も alphabet も正しく表示できる。
コード=utf8	文字数=24	バイト数=52
|日-本-語-も| |a-l-p-h-a-b-e-t| |も-正-し-く-表-示-で-き-る|。-
> 

#ところで、use bytes, no bytes の切り替えが完全には実装されていないよう
#ですね。length($_[0])の結果が(文字/バイトの)コンテキストにかかわらず、
#バイト数になってしまいました。しかし、$_[0]=~/.*/; length($&); とやる
#とuse bytesのときはバイト数が、no bytesのときは文字数が返るんですね。
#あら不思議。

以下、FileFilter.pm とサンプルプログラムのソースです。
これを動かすためには、Perl 5.6 本体の他に、Jcode, Filter の
両モジュールと、4/4の岡部さんのメールにある SJIS.pm が必要です。

# EUC コードをお使いの場合には、ソース中の sjis という記述を
# 適宜 euc に置き換えてお試しください。(当然 SJIS.pm の名前も^^)

====================<test.plここから>====================
#!/usr/local/bin/perl

use utf8;
use Jcode;

use FindBin qw($Bin);
use lib $Bin;
use SJIS;
use FileFilter;

sub chars {
    no bytes;
    $_[0] =~ /.*/;
    return length($&);
    #return length($_[0]);
}
sub bytes {
    use bytes;
    $_[0] =~ /.*/;
    return length($&);
    #return length($_[0]);
}

my $jcode = new Jcode;
my $in  = new FileFilter("<&STDIN",
			 sub{ $jcode->set(join('', at _),sjis)->utf8 });
my $out = new FileFilter(">&STDOUT",
			 sub{ map{ $jcode->set($_,utf8)->sjis }@_ });
$out->autoflush(1);
$out->print("単語の境界に'|'を、それ以外の個所に'-'を挿入して表示します。\n");
while(print '> ' and $_ = $in->readline){
    chomp;
    $out->printf("コード=%s\t文字数=%d\tバイト数=%d\n",
		 scalar Jcode::getcode($_), chars($_), bytes($_));
    s/(\b)|\B/defined($1)?'|':'-'/ge;
    $out->print($_,"\n");
}
====================<test.plここまで>====================

====================<FileFilter.pmここから>====================
package FileFilter;
use strict;
use Carp;
use FileHandle;

use vars qw(@ISA);
@ISA = qw(FileHandle);

sub new {
    my $type = shift;
    my $class = ref($type) || $type;
    my $filter = pop;
    ref($filter) eq 'CODE' or croak "Bad option for FileFilter\n";
    my $self = $class->SUPER::new(@_);
    %{*$self}->{filter} = $filter;
    return $self;
}

sub print {
    my $self = shift;
    if( my $filter = %{*$self}->{filter} ){
	$self->SUPER::print($filter->(@_));
    }else{
	$self->SUPER::print(@_);
    }
}

sub printf {
    my $self = shift;
    if( my $filter = %{*$self}->{filter} ){
	$self->SUPER::print($filter->(sprintf(shift, at _)));
    }else{
	$self->SUPER::printf(shift, at _);
    }
}

sub readline {
    my $self = shift;
    if( my $filter = %{*$self}->{filter} ){
	return( $filter->(scalar(<$self>)) );
    }else{
	return( scalar(<$self>) );
    }
}

sub readlines {
    my $self = shift;
    if( my $filter = %{*$self}->{filter} ){
	return( $filter->(<$self>) );
    }else{
	return( <$self> );
    }
}

1;
====================<FileFilter.pmここまで>====================

--
$p='Perl'; $_='Masahiro Mishima'; sub _{pack'c*',$x=110+ at _*5,$x+1}
tr/oma/fa_/;s/./chr(ord($&)+2)/ge;@x=(sort(grep{!$_{$_}++}split//),
$p=~/(.(..).)/);$x[7]=~s/^/_/e;$x[8].=_ 1;for(@w=(47,1639,8,31259))
{s/\d/$x[$&+1]/g} print ucfirst "@w.\n";



More information about the Kansai-pm mailing list