Che*_*eso 6 optimization perl parsing field text-files
虽然这是非常基本的,但我找不到类似的问题,所以如果你知道现有的问题/解决方案,请链接到一个.
我有一个.txt大约2MB和大约16,000行的文件.每个记录长度为160个字符,阻塞因子为10.这是一种较旧的数据结构类型,几乎看起来像制表符分隔文件,但是分隔是单字符/空格.
首先,我glob对目录的.txt文件-从来就没有在一个时间该目录多个文件,所以这种尝试本身可以是低效的.
my $txt_file = glob "/some/cheese/dir/*.txt";
Run Code Online (Sandbox Code Playgroud)
然后我用这一行打开文件:
open (F, $txt_file) || die ("Could not open $txt_file");
Run Code Online (Sandbox Code Playgroud)
根据这个文件的数据字典,我substr()在while循环中使用Perl的函数解析每一行中的每个"字段" .
while ($line = <F>)
{
$nom_stat = substr($line,0,1);
$lname = substr($line,1,15);
$fname = substr($line,16,15);
$mname = substr($line,31,1);
$address = substr($line,32,30);
$city = substr($line,62,20);
$st = substr($line,82,2);
$zip = substr($line,84,5);
$lnum = substr($line,93,9);
$cl_rank = substr($line,108,4);
$ceeb = substr($line,112,6);
$county = substr($line,118,2);
$sex = substr($line,120,1);
$grant_type = substr($line,121,1);
$int_major = substr($line,122,3);
$acad_idx = substr($line,125,3);
$gpa = substr($line,128,5);
$hs_cl_size = substr($line,135,4);
}
Run Code Online (Sandbox Code Playgroud)
有谁能建议更有效/首选的方法?
它在我看来你在这里使用固定宽度字段.真的吗?如果是,unpack功能就是您所需要的.您提供字段的模板,它将从这些字段中提取信息.有一个教程可用,模板信息的文档中找到pack它unpack的逻辑相反.仅作为一个基本的例子:
my @values = unpack("A1 A15 A15 ...", $line);
Run Code Online (Sandbox Code Playgroud)
其中'A'表示任何文字字符(据我所知),数字是多少.unpack有些人使用它有很多艺术,但我相信这足以满足基本用途.
使用该选项编译和缓存的单个正则表达式/o是最快的方法。我使用 Benchmark 模块以三种方式运行你的代码并得出:
Rate unpack substr regexp
unpack 2.59/s -- -59% -67%
substr 6.23/s 141% -- -21%
regexp 7.90/s 206% 27% --
Run Code Online (Sandbox Code Playgroud)
输入是一个包含 20k 行的文件,每行有相同的 160 个字符(字符重复 16 次0123456789)。因此它的输入大小与您正在使用的数据相同。
该方法从最慢到最快Benchmark::cmpthese()输出子例程调用。第一列告诉我们子例程每秒可以运行多少次。正则表达式方法是最快的。不像我之前所说的那样打开包装。对于那个很抱歉。
基准代码如下。打印语句作为健全性检查。这是为 darwin-thread-multi-2level 构建的 Perl 5.10.0。
#!/usr/bin/env perl
use Benchmark qw(:all);
use strict;
sub use_substr() {
print "use_substr(): New itteration\n";
open(F, "<data.txt") or die $!;
while (my $line = <F>) {
my($nom_stat,
$lname,
$fname,
$mname,
$address,
$city,
$st,
$zip,
$lnum,
$cl_rank,
$ceeb,
$county,
$sex,
$grant_type,
$int_major,
$acad_idx,
$gpa,
$hs_cl_size) = (substr($line,0,1),
substr($line,1,15),
substr($line,16,15),
substr($line,31,1),
substr($line,32,30),
substr($line,62,20),
substr($line,82,2),
substr($line,84,5),
substr($line,93,9),
substr($line,108,4),
substr($line,112,6),
substr($line,118,2),
substr($line,120,1),
substr($line,121,1),
substr($line,122,3),
substr($line,125,3),
substr($line,128,5),
substr($line,135,4));
#print "use_substr(): \$lname = $lname\n";
#print "use_substr(): \$gpa = $gpa\n";
}
close(F);
return 1;
}
sub use_regexp() {
print "use_regexp(): New itteration\n";
my $pattern = '^(.{1})(.{15})(.{15})(.{1})(.{30})(.{20})(.{2})(.{5})(.{9})(.{4})(.{6})(.{2})(.{1})(.{1})(.{3})(.{3})(.{5})(.{4})';
open(F, "<data.txt") or die $!;
while (my $line = <F>) {
if ( $line =~ m/$pattern/o ) {
my($nom_stat,
$lname,
$fname,
$mname,
$address,
$city,
$st,
$zip,
$lnum,
$cl_rank,
$ceeb,
$county,
$sex,
$grant_type,
$int_major,
$acad_idx,
$gpa,
$hs_cl_size) = ( $1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12,
$13,
$14,
$15,
$16,
$17,
$18);
#print "use_regexp(): \$lname = $lname\n";
#print "use_regexp(): \$gpa = $gpa\n";
}
}
close(F);
return 1;
}
sub use_unpack() {
print "use_unpack(): New itteration\n";
open(F, "<data.txt") or die $!;
while (my $line = <F>) {
my($nom_stat,
$lname,
$fname,
$mname,
$address,
$city,
$st,
$zip,
$lnum,
$cl_rank,
$ceeb,
$county,
$sex,
$grant_type,
$int_major,
$acad_idx,
$gpa,
$hs_cl_size) = unpack(
"(A1)(A15)(A15)(A1)(A30)(A20)(A2)(A5)(A9)(A4)(A6)(A2)(A1)(A1)(A3)(A3)(A5)(A4)(A*)", $line
);
#print "use_unpack(): \$lname = $lname\n";
#print "use_unpack(): \$gpa = $gpa\n";
}
close(F);
return 1;
}
# Benchmark it
my $itt = 50;
cmpthese($itt, {
'substr' => sub { use_substr(); },
'regexp' => sub { use_regexp(); },
'unpack' => sub { use_unpack(); },
}
);
exit(0)
Run Code Online (Sandbox Code Playgroud)