2011-02-06 127 views
8

我有很多的文本文件與固定寬度的字段:解析固定寬度的文件

<c>  <c>  <c> 
Dave Thomas 123 Main 
Dan  Anderson 456 Center 
Wilma Rainbow 789 Street 

文件的其餘部分是在一個類似的格式,其中<c>將迎來一列的開始,但他們有各種(未知的)列寬度&。解析這些文件的最佳方法是什麼?

我試着用Text::CSV,但因爲沒有分隔符,很難得到一致的結果(除非我正在使用的模塊錯誤):

my $csv = Text::CSV->new(); 
$csv->sep_char (' '); 

while (<FILE>){ 
    if ($csv->parse($_)) { 
     my @columns=$csv->fields(); 
     print $columns[1] . "\n"; 
    } 
} 
+1

你爲什麼反對「解析」標籤?這是一個解析問題。你在Perl中需要一個解決方案並不意味着它不是一個解析問題。 – zwol 2011-02-06 02:31:27

+0

,因爲我不想要一個通用的解決方案 – 2011-02-06 02:33:00

+0

也許我誤解了......我認爲把「解析」放在那裏會帶來一大堆與我的情況無關的解決方案(即python,php等)。 ..thx – 2011-02-06 02:42:19

回答

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' 
      ] 
     ]; 
3

只需使用Perl的unpack功能。事情是這樣的:

while (<FILE>) { 
    my ($first,$last,$street) = unpack("A9A25A50",$_); 

    <Do something ....> 
} 

裏面的解壓模板中,「A ###」,你可以把該字段的寬度爲每個A. 有多種其他格式,您可以使用混合和匹配,即整數字段等... 如果文件寬度固定,如大型機文件,那麼這應該是最簡單的。

6

CPAN來救援!

DataExtract::FixedWidth不僅分析固定寬度的文件,但(基於POD)似乎足夠聰明,可以根據標題行自行計算列寬!