在Perl中使用相同的变量来打开和关闭foreach循环中的文件

时间:2016-03-19 19:19:24

标签: perl variable-assignment filehandle

考虑到变量声明,我很难理解这一点。场景:我有一个包含十个单词的文件,每行一个。首先,我想循环遍历文件并根据数据创建新文件。实施例

banana
apple
coconut
strawberry

-->

banana.txt
apple.txt
coconut.txt
strawberry.txt

我遇到的第一个问题是:如何为循环中的每个文件分配文件句柄的唯一变量?我会写这样的东西,但我不知道如果这是要走的路:

open(my $tokensfh, '<', $tokensfile)
  or die "cannot open file $tokensfile";
chomp(my @tokenslines = <$tokensfh>);
close $tokensfh;

foreach my $token(@tokenslines) {
  open(my $token.'fh', '>>', $token."data.txt");
} 

接下来,我将其他数据与$令牌匹配,但我不确定如何处理这些变量:

foreach my $somedata(@data) {
    my $datatoken = $somedata=~  /<fruit>(.+)<\/fruit>/;

    # Do I need a new variable name here?
    foreach my $tokensline(@tokenslines) {
        if ($datalinetoken eq $datatoken ) {
          # print $somedata to specific file
          print $tokensline.'fh' "average run time\n";
        }
    }
}

我是否需要新的变量名?如果没有,如何在不获取变量赋值问题的情况下重新使用早期变量?有一个更好的方法吗? (请回答所有问题。)

2 个答案:

答案 0 :(得分:3)

不要这样做。使用变量变量名称非常讨厌。有关原因的更详细说明,请参阅此链接:http://perl.plover.com/varvarname.html

如果您需要命名文件句柄,那么使用文件句柄的散列要好得多。哈希是一个可移植的命名空间,这正是您需要的。

所以:

my %fh_for; 
foreach my $token ( @tokenlines ) { 
   open ( my $fh_for{$token}, '>', "$token.txt" ) or die $!; 
}

foreach my $datalinetoken (@tokenslines) {
    if ($datalinetoken eq $datatoken ) {
      # print $somedata to specific file
      print {$fh_for{$datalinetoken}} "average run time\n";
    }
}

然后,您可以写入由您的令牌名称键入的文件句柄,而不需要动态变量命名的肮脏混乱。请注意,我已将您的fh包含在{}中 - 有必要告诉perl'评估此'。

答案 1 :(得分:3)

只要在不同的范围内声明它们,就可以重复使用相同的全局变量名称。如果你声明两次相同的变量,Perl会警告你。我在下面的代码中使用了相同的名称$fh作为文件句柄而没有任何后果

在这种情况下,您需要为大多数程序打开文件句柄,因此您需要一整套程序,看起来最简单的方法是使用哈希,这样您就可以选择正确的文件句柄通过使用令牌字符串索引哈希

看起来像这样。请注意,我已使用use autodie来避免必须明确检查每个IO操作的状态。您可能还需要考虑是否需要处理appleAPPLEApple之间的差异,此时此差异将创建三个文件句柄(并且会让Windows感到困惑!)

哦,顺便说一下,用while逐行处理每个文件而不是将它全部读入数组并从那里处理数据会更好

use strict;
use warnings 'all';
use v5.14.1; # For autodie
use autodie;

use constant TOKENS_FILE => 'tokens.txt';
use constant XML_FILE    => 'data.xml';

my %token_fh;

{
    open my $fh, '<', TOKENS_FILE;

    while ( <$fh> ) {
        chomp;
        open $token_fh{$_}, '>', "${_}data.txt";
    }
}

{
    open my $fh, '<', XML_FILE;

    while ( <$fh> ) {

        next unless my ($token) = m|<fruit>(.+)</fruit>|;
        next unless my $fh = $token_fh{$token};

        print $fh "average run time\n";
    }
}

close $_ for values %token_fh;


另一种方法是完全忘记令牌文件,只打开XML中遇到的文件。这看起来像这样

use strict;
use warnings 'all';
use v5.14.1; # For autodie
use autodie;

use constant XML_FILE    => 'data.xml';

my %token_fh;

open my $fh, '<', XML_FILE;

while ( <$fh> ) {

    next unless my ($token) = m|<fruit>(.+)</fruit>|;

    unless ( exists $token_fh{$token} ) {
        open $token_fh{$token}, '>', "${token}data.txt";
    }
    my $fh = $token_fh{$token};

    print $fh "average run time\n";
}

close $_ for values %token_fh;