【问题标题】:Perl - Parse blocks from text filePerl - 从文本文件中解析块
【发布时间】:2012-10-25 22:22:29
【问题描述】:

首先,如果您认为这是重复的,我深表歉意。我环顾四周,发现了一些非常相似的问题,但我要么迷路了,要么这不是我认为我需要的,因此无法提出正确的实现。

问题:

所以我有一个 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().',
                },
           },
    },

};

解决此问题的最佳方法是什么?我应该更改生成日志的格式以使自己更容易吗?如果您需要更多信息,请询问。提前谢谢你。 :)

【问题讨论】:

    标签: regex perl parsing logging filehandler


    【解决方案1】:

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

    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,
          };
       }
    }
    

    我应该更改生成日志的格式

    您的时间戳似乎不明确。在大多数时区,一年中的一个小时会重复。

    【讨论】:

    • "您的时间戳似乎不明确。在大多数时区,一年中的一个小时是重复的。"你这是什么意思?你建议我如何制作时间戳?更准确?
    • @Dylan,在这里,由于时钟变化,时钟在 11/4/2012 0:00 后 90 分钟和同一时间后 150 分钟都显示为 11/4/2012 1:30。如有必要,您可以包括与 UTC 的偏移量以消除歧义。
    【解决方案2】:

    如果您可以将其输出为 XML,那么使用XML::Simple 将其读入会非常容易

    【讨论】:

    • 嗯。当我有机会时,我会进一步研究,谢谢。
    【解决方案3】:

    虽然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 子例程来保持逻辑,即确定该条目属于循环的哪个位置。

    注意:我在每条数据后附加一个空格。我这样做是为了使代码更简单,因为您的某些消息可能需要多于一行。还有其他方法可以处理这个问题,但我试图保持循环尽可能干净,并尽可能少使用 if 语句。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-09
      • 1970-01-01
      • 1970-01-01
      • 2014-09-04
      • 2015-10-14
      • 2023-03-15
      • 2016-01-22
      • 2012-06-08
      相关资源
      最近更新 更多