我想使用
myscript.pl targetfolder/*
从ASCII文件中读取一些数字。
@list = <@ARGV>;
# Is the whole file or only 1st line is loaded?
foreach $file ( @list ) {
open (F, $file);
}
# is this correct to judge if there is still file to load?
while ( <F> ) {
match_replace()
}
sub match_replace {
# if I want to read the 5th line in downward, how to do that?
# if I would like to read multi lines in multi array[row],
# how to do that?
if ( /^\sName\s+/ ) {
$name = $1;
}
}
答案 0 :(得分:1)
我建议您仔细阅读perlintro
-它会为您提供许多您需要的信息。附加评论:
始终使用strict
和warnings
。前者将强制执行一些良好的编码习惯(例如声明变量),而后者将告知您潜在的错误。例如,您显示的代码产生的一个警告将是readline() on unopened filehandle F
,提示您F
当时未打开(更多内容在下面)。
@list = <@ARGV>;
:这有点棘手,我不建议您使用-实际上,您正在使用glob
,而扩展targetfolder/*
是您的shell应该做的事情,如果您使用的是Windows,则建议不要手动进行Win32::Autoglob
。
foreach ... { open ... }
:打开文件后,您将不执行任何操作-从文件读取的循环必须位于foreach
内。
“是整个文件还是仅加载了第一行?” open
不会从文件中读取任何内容,它只是打开文件并提供了然后需要从中读取文件句柄(您将其命名为F
)。
我强烈建议您使用更现代的三参数形式open
并检查错误,并使用词法文件句柄,因为它们的作用域不是全局的,如{{1 }}。
“判断是否还有文件要加载是否正确?” 是的,open my $fh, '<', $file or die "$file: $!";
是逐行读取文件的好方法,并且从文件中读取所有内容后,循环将结束。您可能需要使用更明确的形式while (<$filehandle>)
,以便您的变量具有名称,而不是默认的$_
变量-确实会使代码更冗长,但是如果您只是开始可能是一件好事。
while (my $line = <$filehandle>)
:您没有将任何参数传递给match_replace()
。即使这段代码仍然可以“工作”,它还是通过全局变量sub
将当前行传递到sub
上,但这不是一个好习惯,因为一旦脚本被执行,它将造成混乱并且容易出错。开始变长。
$_
:由于您已经命名了if (/^\sName\s+/){$name = $1;}
sub
,所以我猜您想进行搜索和替换操作。在Perl中,这称为match_replace
,您可以在perlrequick
和perlretut
中进行了解。至于您显示的代码,您正在使用s/search/replacement/
,但是您的正则表达式中没有任何“捕获组”($1
)-您可以在这两个代码中阅读链接。
“如果我想向下阅读第五行,该怎么做?” 与Perl一样,有多种方法可以做到这一点(TIMTOWTDI)。一种方法是使用range operator ..
-您可以通过在while循环开始时说(...)
来跳过第一行至第四行,这将针对特殊的$.
变量测试这些行号,跟踪最近读取的行号。
“,如果我想读取多数组[row]中的多行,该怎么做?” 一种方法是使用push
添加当前行行到数组的末尾。由于将文件中的行保留在数组中可能会占用更多的内存,尤其是对于大文件,因此,强烈建议确保您仔细考虑要在此处使用的算法。您尚未解释为什么您想将内容保留在数组中,所以在这里我不能更具体地说明。
这么说了之后,这就是我编写该代码的方式。我使用Data::Dumper
添加了一些调试代码-查看脚本正在使用的数据总是很有帮助的。
next if 1..4;
上面的代码明确地在@ARGV
上循环并打开每个文件,我在上面确实说过,更详细的代码可以帮助您了解正在发生的事情。我只是想指出Perl的一个不错的功能,即“魔术” #!/usr/bin/env perl
use warnings;
use strict;
use Data::Dumper; # for debugging
$Data::Dumper::Useqq=1;
for my $file (@ARGV) {
print Dumper($file); # debug
open my $fh, '<', $file or die "$file: $!";
while (my $line = <$fh>) {
next if 1..4;
chomp($line); # remove line ending
match_replace($line);
}
close $fh;
}
sub match_replace {
my ($line) = @_; # get argument(s) to sub
my $name;
if ( $line =~ /^\sName\s+(.*)$/ ) {
$name = $1;
}
print Data::Dumper->Dump([$line,$name],['line','name']); # debug
# ... do more here ...
}
运算符(在perlop
under "I/O Operators"中讨论),它将自动打开<>
中的文件并从中读取行。 (只有一小件事,如果我想使用@ARGV
变量并让其计算每个文件的行数,则需要使用下面显示的$.
块,这在{ {3}}。)这将是编写第一个循环的更“惯用”的方式:
continue