我有很多带有固定宽度字段的文本文件:
<c> <c> <c>
Dave Thomas 123 Main
Dan Anderson 456 Center
Wilma Rainbow 789 Street
其余文件采用相似的格式,其中<c>
将标记列的开头,但它们具有各种(未知)列&amp;空间宽度。解析这些文件的最佳方法是什么?
我尝试使用Text::CSV
,但由于没有分隔符,因此很难获得一致的结果(除非我使用的模块错误):
my $csv = Text::CSV->new();
$csv->sep_char (' ');
while (<FILE>){
if ($csv->parse($_)) {
my @columns=$csv->fields();
print $columns[1] . "\n";
}
}
答案 0 :(得分:12)
正如user604939所提到的,unpack
是用于固定宽度字段的工具。但是,unpack
需要传递模板才能使用。由于您说您的字段可以更改宽度,因此解决方案是从文件的第一行构建此模板:
my @template = map {'A'.length} # convert each to 'A##'
<DATA> =~ /(\S+\s*)/g; # split first line into segments
$template[-1] = 'A*'; # set the last segment to be slurpy
my $template = "@template";
print "template: $template\n";
my @data;
while (<DATA>) {
push @data, [unpack $template, $_]
}
use Data::Dumper;
print Dumper \@data;
__DATA__
<c> <c> <c>
Dave Thomas 123 Main
Dan Anderson 456 Center
Wilma Rainbow 789 Street
打印:
template: A8 A10 A* $VAR1 = [ [ 'Dave', 'Thomas', '123 Main' ], [ 'Dan', 'Anderson', '456 Center' ], [ 'Wilma', 'Rainbow', '789 Street' ] ];
答案 1 :(得分:6)
CPAN救援!
DataExtract::FixedWidth不仅解析固定宽度的文件,而且(基于POD)似乎足够智能,可以自己从标题行中找出列宽!
答案 2 :(得分:3)
只需使用Perl的unpack功能即可。像这样:
while (<FILE>) {
my ($first,$last,$street) = unpack("A9A25A50",$_);
<Do something ....>
}
在解包模板中,“A ###”,你可以为每个A放置字段的宽度。 您可以使用各种其他格式来混合和匹配,即整数字段等... 如果文件是固定宽度的,就像大型机文件一样,那么这应该是最简单的。