2012-11-06 124 views
2

首先,如果您觉得这是重复的,我表示歉意。我环顾四周,发现了一些非常相似的问题,但我要么迷路了,要么不是我认为我需要的东西,因此不能提出适当的实施方案。Perl - 从文本文件中解析块

问题:

所以我有一个包含由另一个脚本生成的条目一个txt文件(我可以编辑如何生成这些条目的格式,如果你能提出一个更好的办法来设置格式):

SR4 Pool2 
11/5/2012 13:45 
---------- 
Beginning Wifi_Main(). 

SR4 Pool2 
11/8/2012 8:45 
---------- 
This message is a 
multiline message. 

SR4 Pool4 
11/5/2012 14:45 
---------- 
Beginning Wifi_Main(). 

SR5 Pool2 
11/5/2012 13:48 
---------- 
Beginning Wifi_Main(). 

而且我做了一个Perl脚本解析文件:

#!C:\xampp-portable\perl\bin\perl.exe 

use strict; 
use warnings; 
#use Dumper; 

use CGI 'param','header'; 
use Template; 
#use Config::Simple; 

#Config::Simple->import_from('config.ini', \%cfg); 

my $cgh = CGI->new; 
my $logs = {}; 
my $key; 

print "Content-type: text/html\n\n"; 

open LOG, "logs/Pool2.txt" or die $!; 


while (my $line = <LOG>) { 
    chomp($line); 

} 

print $logs; 

close LOG; 

我的目标是在看起来像这样结束的哈希:

$logs = { 
    SR4 => { 
      Pool2 => { 
       { 
        time => '11/5/2012 13:45', 
        msg => 'Beginning Wifi_NDIS_Main().', 
       }, 
       { 
        time => '11/8/2012 8:45', 
        msg => 'This message is a multiline message.', 
       }, 
      }, 
      Pool4 => { 
       { 
        time => '11/5/2012 13:45', 
        msg => 'Beginning Wifi_NDIS_Main().', 
       }, 
      }, 
    }, 
    SR5 => { 
      Pool2 => { 
       { 
        time => '11/5/2012 13:45', 
        msg => 'Beginning Wifi_NDIS_Main().', 
       }, 
      }, 
    }, 

};

要做这件事的最好方法是什么?我应该更改生成的日志的格式以使其更容易吗?如果您需要更多信息,请询问。先进的谢谢你。 :)

回答

2

如果你所能输出为XML,阅读它会与XML::Simple

+0

嗯。当我有机会的时候,我会更加关注这个问题,谢谢。 – Dylan

2

格式embarrasingly容易是没有意义的。你在第三级使用了散列,但是你没有为这些值指定键。我假设它应该是一个数组。

my %logs; 
{ 
    local $/ = ""; # "Paragraph mode" 
    while (<>) { 
     my @lines = split /\n/; 
     my ($x, $y) = split ' ', $lines[0]; 
     my $time = $lines[1]; 
     my $msg = join ' ', @lines[3..$#lines]; 
     push @{ $logs{$x}{$y} }, { 
     time => $time, 
     msg => $msg, 
     }; 
    } 
} 

我应该改变生成的日志

你的时间戳似乎是暧昧的格式。在大多数时区,一年的一个小时会重复。

+0

“您的时间戳看起来含糊不清,在大多数时区,一年中的一个小时会重复。” 这是什么意思?你如何建议我做一个时间戳?更精确? – Dylan

+0

@Dylan,在这里,由于时钟变化,在'11/4/2012 0:00'后90分钟和同一时间后150分钟,时钟读取'11/4/2012 1:30'。如果需要,您可以包含来自UTC的偏移量以消除歧义。 – ikegami

0

虽然Karthik T使用XML的想法很有意义,我也会考虑它,但我不确定这是否是最佳路线。第一个问题是首先将它放在XML格式中。

其次是XML格式可能不那么容易被解析。当然,XML :: Simple模块将一次性读取整个事件,然后您必须解析XML数据结构本身。

如果您可以根据需要设置输出,请使用易于解析的格式。我喜欢使用前缀数据标识符。在下面的例子中,每条数据都有自己的标识符。该ER:告诉我,当我达到创纪录的末尾:

DT: 11/5/2012 13:35 
SR: SR4 
PL: Pool2 
MG: Beginning Wifi_Main(). 
ER: 
DT: 1/8/2012 8:45 
SR: SR4 
PL: Pool2 
MG: This message is a 
MG: multiline message. 
ER: 

解析这个输出是直截了当:

my %hash; 
while ($line = <DATA>) { 
    chomp $line; 
    if (not $line eq "ER:") { 
     my ($key, $value) = split (": ", $line); 
     $hash{$key} .= "$value "; #Note trailing space! 
    } 
    else { 
     clean_up_hash (\%hash); #Remove trailing space on all values 
     create_entry (\%log, \%hash); 
     %hash =(); 
    } 
} 

我喜欢用每当我开始越来越复杂的数据结构类,我可能会创造一个Local::Log类和子类来存储日志的每一层。然而,这不是绝对必要的,也不是你的问题的一部分。不过,我会使用一个create_entry子例程来保持确定日志中该条目​​在循环内所处位置的逻辑。

注意:我在每段数据后面追加一个空格。我这样做是为了使代码更简单,因为你的一些消息可能需要多行。还有其他方法可以解决这个问题,但我试图尽可能保持循环尽可能干净,并尽可能减少陈述。