2014-10-11 42 views
3

我對Perl非常陌生,編寫Perl腳本非常困難,它將成功解析結構化文本文件。解析Perl中的結構化文本文件

我有一個像這樣的文件的集合:

name: 
    John Smith 
occupation: 
    Electrician 
date of birth: 
    2/6/1961 
hobbies: 
    Boating 
    Camping 
    Fishing 

等。字段名稱後面總是跟一個冒號,並且與這些字段關聯的所有數據總是由單個選項卡(\ t)縮進。

我想創建一個哈希,將直接與字段名稱字段內容,這樣的聯想:

$contents{$name} = "John Smith" 
$contents{$hobbies} = "Boating, Camping, Fishing" 

或者類似的規定。

到目前爲止,我已經能夠將所有字段名稱自己分別存儲到散列表中,但是我沒有將字段數據轉換爲可以很好地存儲在散列表中的表單。顯然,用標籤替換/拆分換行符將不起作用(我試過了,有點天真)。我還嘗試了一種粗略的前瞻性方法,在該方法中,我從文件創建了一個重複的行數組,並使用它來計算字段邊界的位置,但就內存消耗而言並不是那麼好。

FWIW,目前我正在逐行閱讀文件,但我並不完全相信這是最好的解決方案。有沒有辦法以直接的方式進行解析?

回答

5

逐行讀取文件是一個好方法。這裏我創建了一個數組引用的哈希。這是你如何閱讀一個文件。你可以用這種方式讀取每個文件,並將數組的哈希值放入數組哈希值的哈希中。

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

my %contents; 
my $key; 
while(<DATA>){ 
    chomp; 
    if (s/:\s*$//) { 
     $key = $_; 
    } else { 
     s/^\s+//g; # remove extra whitespace 
     push @{$contents{$key}}, $_; 
    } 
} 
print Dumper \%contents; 

__DATA__ 
name: 
    John Smith 
occupation: 
    Electrician 
date of birth: 
    2/6/1961 
hobbies: 
    Boating 
    Camping 
    Fishing 

輸出:

$VAR1 = { 
      'occupation' => [ 
          'Electrician' 
          ], 
      'hobbies' => [ 
          'Boating', 
          'Camping', 
          'Fishing' 
         ], 
      'name' => [ 
         'JohnSmith' 
        ], 
      'date of birth' => [ 
           '2/6/1961' 
           ] 
     }; 
+2

可能最好不要使用's/\ s + // g;''去除所有額外的空格' - 這對名稱很有用! ';)' – 2014-10-11 15:38:39

+2

@ialarmedalien看起來像米勒更新到領先的空白。絕對要搞個名字,打個電話。只是想拋出一些東西來顯示如果你需要的話,你可以在這些元素上進行處理! – chilemagic 2014-10-11 16:57:47

+0

這正是我所需要的 - 它比我想象的要容易得多。謝謝! – MARS 2014-10-12 01:51:10

2

這個文本文件實際上是相當接近YAML。而且它不是很難把它轉換成一個有效的YAML文件:

一旦你有,你可以使用YAML YAML文件::微小的或其他模塊來解析它,從而導致更乾淨的代碼:

#!/usr/bin/perl 
use strict; 
use warnings; 

use YAML::Tiny; 
use Data::Dumper; 

convert('./data.yaml', 'output.yaml'); 
parse('output.yaml'); 

sub parse { 
    my $yaml = shift; 
    my $yamlobj = YAML::Tiny->read($yaml); 

    my $name = $yamlobj->[0]->{name}[0]; 
    my $occ  = $yamlobj->[0]{occupation}[0]; 
    my $birth = $yamlobj->[0]{'date of birth'}[0]; 
    my $hobbies = $yamlobj->[0]{hobbies}; 

    my $hobbiestring = join ", ", @$hobbies; 

    my $contents = { 
     name  => $name, 
     occupation => $occ, 
     birth  => $birth, 
     hobbies => $hobbiestring, 
    }; 

    print "#RESULT:\n\n"; 
    print Dumper($contents); 
} 

sub convert { 
    my ($input, $output) = @_; 

    open my $infh, '<', $input or die "$!"; 
    open my $outfh, '>', $output or die "$!"; 

    while (my $line = <$infh>) { 
     $line =~ s/^\s+\K$/-/g; 
     print $outfh ($line); 
    } 
}