结合使用grep
,cut
,sed
,awk
等,在外壳中通常很容易加载文件和排序列。
但是,当我不得不在Perl中执行此操作时,我经常会使用许多拆分(一个接一个的正则表达式)来做冗长而痛苦的事情,结果是看起来像这样的肮脏代码:
open $FH, "<", $file;
@file = <$FH>;
close $FH;
foreach $line (@file) {
( $foo, $bar, $some, $thing) = ( split(/,/, $line) )[3,8,9,15]
( $new_some ) = (split(/-/, $some))[2];
($new_foo = $foo) =~ s/xx//;
$uc_bar = uc($bar);
# and so on.....
}
难道没有更优雅的方式来做这些事情(拆分字段,替换模式等)吗?还是更“快速”的方式(不一定优雅)?
还有一种方法可以在加载时仅加载文件的必需部分(无需加载内存中的所有内容,而是在加载之前进行过滤)?
答案 0 :(得分:2)
优雅是主观的,但我至少可以回答您的一个问题,并提出一些可能会缩短或改善您的代码的事情。
“有没有一种方法可以在加载时仅加载文件的必需部分” -在显示的代码中,我认为不需要将整个文件加载到内存中。逐行处理文件的典型模式,相当于Perl的-n
and -p
switches的模式,是这种模式:
open my $fh, '<', $file or die "$file: $!";
while (<$fh>) { # reads line into $_
my @fields = split; # splits $_ on whitespace, like awk
my ($foo, $bar, $some, $thing) = @fields[3,8,9,15];
...
}
close $fh;
我认为这很优雅,但是根据您的写作,我想您正在将其与可能包含100个字符的管道命令的单行代码进行比较。 Perl也可以做到这一点:正如评论中已经提到的,看看开关-n
, -p
, -a
, -F
, and -i
。如果显示一些具体的示例,您可能会得到一些答复,说明如何使用Perl来缩短操作时间。
但是,如果您要做更多的事情,那么通常最好将其扩展为上面的脚本。恕我直言,将内容放到脚本中可以赋予您更多功能:它不像命令行历史记录那样短暂,它更易于扩展,使用模块也更容易,您可以添加命令行选项,处理多个文件等等。例如,通过以下代码片段,您将获得Text::CSV
的全部功能-支持引号,转义,多行字符串等。
use Text::CSV;
my $csv = Text::CSV->new({binary=>1, auto_diag=>2, eol=>$/});
open my $fh, '<', $file or die "$file: $!";
while ( my $row = $csv->getline($fh) ) {
...
$csv->print(select, $row);
}
$csv->eof or $csv->error_diag;
close $fh;
您可能还想查看该模块的csv
函数,该函数在短函数中提供了很多功能。如果您仍然认为这只是“痛苦的” 和“肮脏的” 的全部,并且您希望用更少的代码来完成工作,那么可以使用一些捷径将整个文件插入到存储器my $data = do { local (*ARGV, $/) = $file; <> };
或与-i
命令行开关相同的示例:
local ($^I, @ARGV) = ('.bak', $file);
while (<>) {
# s///; or @F=split; or whatever
print; # prints $_ back out
}
我喜欢Perl的一件事是,它可以让您以多种不同的方式表达自己的想法-无论是要编写一个非常简短的脚本来完成一项一次性任务,还是编写一个大型OO项目,{ {3}}