Perl - разбирать блоки из текстового файла

Во-первых, я прошу прощения, если вы считаете, что это дубликат. Я огляделся и нашел несколько очень похожих вопросов, но я либо заблудился, либо это было не совсем то, что, на мой взгляд, мне нужно, и поэтому не смогло придумать правильную реализацию.

ВОПРОС:

Итак, у меня есть текстовый файл, который содержит записи, сделанные другим скриптом (я могу отредактировать формат для того, как эти записи генерируются, если вы можете предложить лучший способ их форматирования):

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().',
                },
           },
    },

};

Что было бы лучшим способом добиться этого? Должен ли я изменить форматирование сгенерированных журналов, чтобы мне было проще? Если вам нужна дополнительная информация, просто спросите. Заранее благодарю.:)

3 ответа

Если вы можете вывести его в формате XML, его чтение будет очень просто с XML::Simple

Формат не имеет смысла. Вы использовали хэш на третьем уровне, но не указали ключи для значений. Я предполагаю, что это должен быть массив.

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

Должен ли я изменить форматирование сгенерированных журналов

Ваши метки времени кажутся неоднозначными. В большинстве часовых поясов час года повторяется.

Хотя идея 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 заявления как можно.

Другие вопросы по тегам