使用相同的变量在 Perl 的 foreach 循环中打开和关闭文件
Using the same variable to open and close files in foreach loop in Perl
考虑到变量声明,我很难理解这个问题。场景:我有一个包含十个单词的文件,每行一个。首先,我想遍历文件并根据数据创建新文件。例子
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");
}
再往下一点,我将其他数据与 $token 进行匹配,但我不确定如何处理变量:
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";
}
}
}
我需要一个新的变量名吗?如果不需要,我怎样才能重新使用之前的变量而不会出现变量赋值问题?有一个更好的方法吗? (请回答所有问题。)
不要这样做。使用可变的变量名是非常讨厌的。有关原因的更详细解释,请参阅此 link: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 到 'evaluate this'。
您可以重复使用相同的全局变量名,只要它们在不同的作用域中声明即可。如果你两次声明同一个变量,Perl 会警告你。我在下面的代码中使用了相同的名称 $fh
作为文件句柄,没有任何后果
在这种情况下,你需要打开大部分程序的文件句柄,所以你需要一整套,看起来使用哈希最简单,这样你就可以选择正确的通过使用令牌字符串
索引散列来处理文件句柄
它看起来像这样。请注意,我使用 use autodie
来避免必须显式检查每个 IO 操作的状态。您可能还想考虑是否需要处理 apple
、APPLE
和 Apple
之间的差异,目前这将创建三个文件句柄(并且会混淆 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;
考虑到变量声明,我很难理解这个问题。场景:我有一个包含十个单词的文件,每行一个。首先,我想遍历文件并根据数据创建新文件。例子
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");
}
再往下一点,我将其他数据与 $token 进行匹配,但我不确定如何处理变量:
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";
}
}
}
我需要一个新的变量名吗?如果不需要,我怎样才能重新使用之前的变量而不会出现变量赋值问题?有一个更好的方法吗? (请回答所有问题。)
不要这样做。使用可变的变量名是非常讨厌的。有关原因的更详细解释,请参阅此 link: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 到 'evaluate this'。
您可以重复使用相同的全局变量名,只要它们在不同的作用域中声明即可。如果你两次声明同一个变量,Perl 会警告你。我在下面的代码中使用了相同的名称 $fh
作为文件句柄,没有任何后果
在这种情况下,你需要打开大部分程序的文件句柄,所以你需要一整套,看起来使用哈希最简单,这样你就可以选择正确的通过使用令牌字符串
索引散列来处理文件句柄它看起来像这样。请注意,我使用 use autodie
来避免必须显式检查每个 IO 操作的状态。您可能还想考虑是否需要处理 apple
、APPLE
和 Apple
之间的差异,目前这将创建三个文件句柄(并且会混淆 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;