代码之家  ›  专栏  ›  技术社区  ›  Ryan C. Thompson

从实际文件句柄访问Perl的空角度“<>”运算符?

  •  4
  • Ryan C. Thompson  · 技术社区  · 16 年前

    我喜欢使用nifty perl特性,在这里从空角度操作符进行读取 <> 神奇地为您的程序提供了unix过滤器语义,但我希望能够通过一个实际的文件句柄(或 IO::Handle 对象,或类似对象),这样我就可以做一些事情,比如将它传递到子例程等等。有什么办法吗?

    这个问题对谷歌来说特别困难,因为搜索“angle operator”和“filehandle”只是告诉我如何使用angle operator从filehandle中读取。

    3 回复  |  直到 15 年前
        1
  •  9
  •   Chris Lutz    16 年前

    perldoc perlvar 以下内容:

    • ARGV

    循环访问命令行文件名的特殊文件句柄 @ARGV .通常作为角度运算符中的空文件句柄写入 <> . 注意,目前 argv 只有在 <> operator;在其他地方,它只是一个普通的文件句柄,对应于 <> .尤其是传球 \*ARGV 作为期望文件句柄的函数的参数,可能不会导致函数自动读取中所有文件的内容。 @ ARGV .

    我相信,回答你问题的方方面面都是“讨厌说出来,但它不会做你想做的事情”。您可以做的是使函数打开文件名列表,并执行以下操作:

    sub takes_filenames (@) {
      local @ARGV = @_;
      // do stuff with <>
    }
    

    但这可能是你能做到的最好的办法。

        2
  •  6
  •   Sinan Ünür    16 年前

    在Chris Lutz的想法的基础上,这里有一个非常基本的实现:

    #!/usr/bin/perl
    
    package My::ARGV::Reader;
    
    use strict; use warnings;
    use autodie;
    use IO::Handle;
    
    use overload
        '<>' => \&reader,
        '""' => \&argv,
        '0+' => \&input_line_number,
    ;
    
    sub new {
        my $class = shift;
        my $self = {
            names => [ @_ ],
            handles => [],
            current_file => 0,
        };
        bless $self => $class;
    }
    
    sub reader {
        my $self = shift;
    
        return scalar <STDIN> unless @{ $self->{names}};
    
        my $line;
    
        while ( 1 ) {
            my $current = $self->{current_file};
            return if $current >= @{ $self->{names} };
    
            my $fh = $self->{handles}->[$current];
    
            unless ( $fh ) {
                $self->{handles}->[$current] = $fh = $self->open_file;
            }
    
            if( eof $fh ) {
                close $fh;
                $self->{current_file} = $current + 1;
                next;
            }
    
            $line = <$fh>;
            last;
        }
        return $line;
    }
    
    sub open_file {
        my $self = shift;
        my $name = $self->{names}->[ $self->{current_file} ];
        open my $fh, '<', $name;
        return $fh;
    }
    
    sub argv {
        my $self = shift;
        my $name = @{$self->{names}}
                 ? $self->{names}->[ $self->{current_file} ]
                 : '-'
                 ;
        return $name;
    }
    
    sub input_line_number {
        my $self = shift;
        my $fh = @{$self->{names}}
               ? $self->{handles}->[$self->{current_file}]
               : \*STDIN
               ;
        return $fh->input_line_number;
    }
    

    可用于:

    package main;
    
    use strict; use warnings;
    
    my $it = My::ARGV::Reader->new(@ARGV);
    
    echo($it);
    
    sub echo {
        my ($it) = @_;
        printf "[%s:%d]:%s", $it, +$it, $_ while <$it>;
    }
    

    输出:

    [file1:1]:bye bye
    [file1:2]:hello
    [file1:3]:thank you
    [file1:4]:no translation
    [file1:5]:
    [file2:1]:chao
    [file2:2]:hola
    [file2:3]:gracias
    [file2:4]:
    
        3
  •  1
  •   Ryan C. Thompson    15 年前

    看起来这已经实现为 Iterator::Diamond . 迭代器::diamond还禁用perl在读取时使用的2参数打开的魔力。 <ARGV> . 更好的是,它支持阅读 '-' 作为stdin,不启用所有其他魔法。事实上,我可能只是在单个文件中使用它。

    推荐文章