Как я могу прочитать пользовательский шаблон из файла в Perl? - PullRequest
3 голосов
/ 31 декабря 2008

Новогодние пожелания всем.

У меня есть файл журнала ошибок с содержанием в параметре шаблона, result и stderr (stderr может быть в нескольких строках).

$cat error_log

<parameter>:test_tot_count
<result>:1
<stderr>:Expected "test_tot_count=2" and the actual value is 3
test_tot_count = 3
<parameter>:test_one_count
<result>:0
<stderr>:Expected "test_one_count=2" and the actual value is 0
test_one_count = 0
<parameter>:test_two_count
<result>:4
<stderr>:Expected "test_two_count=2" and the actual value is 4
test_two_count = 4
...

Мне нужно написать функцию на Perl для хранения каждого параметра, результата и stderr в массиве или хэш-таблице.

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

my $err_msg = "";
while (<ERR_LOG>)
{
    if (/<parameter>:/)
    {
        s/<parameter>://;
        push @parameter, $_;
    }
    elsif (/<result>:/)
    {
        s/<result>://;
        push @result, $_;
    }
    elsif (/<stderr>:/)
    {
        if (length($err_msg) > 0)
        {
            push @stderr, $err_msg;
        }
        s/<stderr>://;
        $err_msg = $_;
    }
    else
    {
        $err_msg .= $_;
    }
 } 
 if (length($err_msg) > 0)
 {
    push @stderr, $err_msg;
 }

Ответы [ 3 ]

4 голосов
/ 31 декабря 2008

Если вы используете Perl 5.10, вы можете сделать что-то очень похожее на то, что у вас есть сейчас, но с гораздо более приятным макетом, используя заданную / когда структуру:

use 5.010;

while (<ERR_LOG>) {
    chomp;
    given ($_) {
        when ( m{^<parameter>: (.*)}x )  { push @parameter, $1     }
        when ( m{^<result>:    (.*)}x )  { push @result,    $1     }
        when ( m{^<stderr>:    (.*)}x )  { push @stderr,    $1     }
        default                          { $stderr[-1]   .= "\n$_" }
    }
}

Стоит отметить, что для случая по умолчанию здесь, вместо того, чтобы хранить отдельную переменную $ err_msg, я просто нажимаю на @stderr, когда вижу тег stderr, и добавляю к последнему элементу * 1006. * массив, если я вижу продолжение строки. Я добавляю новую строку, когда вижу строки продолжения, так как полагаю, что вы хотите, чтобы они были сохранены.

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

use 5.010;

my @records;

my $prev_key;

while (<ERR_LOG>) {
    chomp;
    given ($_) {
        when ( m{^<parameter>  }x ) { push(@records, {}); continue;          }
        when ( m{^<(\w+)>: (.*)}x ) { $records[-1]{$1} = $2; $prev_key = $1; }
        default                     { $records[-1]{$prev_key} .= "\n$_";     }
    }
}

Здесь мы помещаем новую запись в массив, когда видим поле, добавляем запись в наш хеш всякий раз, когда мы видим пару ключ / значение, и добавляем последнее поле, к которому добавили, если видим строку продолжения , Конечный результат @records выглядит так:

(
    {
        parameter => 'test_one_count',
        result    => 0,
        stderr    => qq{Expected "test_one_count=2" and the actual value is 0\ntest_one_count=0},
    },
    {
        parameter => 'test_two_count',
        result    => 4,
        stderr    => qq{Expected "test_two_count=2" and the actual value is 4\ntest_two_count=4},
    }
)

Теперь вы можете передавать только одну структуру данных, которая содержит все ваши записи, и вы можете добавить больше полей в будущем (даже многострочных), и они будут правильно обрабатываться.

Если вы не используете Perl 5.10, это может быть хорошим поводом для обновления. Если нет, вы можете перевести данные / когда структуры в более традиционные структуры if / elsif / else, но они теряют большую часть своей красоты в преобразовании.

Пол

3 голосов
/ 31 декабря 2008

Главное, что выскакивает при рефакторинге - это повторение в сопоставлении, извлечении и хранении. Примерно такой (непроверенный) код более лаконичен:

my( $err_msg , %data );

while (<ERR_LOG>) {
  if(( my $key ) = $_ =~ s/^<(parameter|result|stderr)>:// ) {
    if( $key eq 'stderr' ) {
      push @{ $data{$key} } , $err_msg if $err_msg;
      $err_msg = $_;
    }
    else { push @{ $data{$key} } , $_ }
  }
  else { $err_msg .= $_ }
}

# grab the last err_msg out of the hopper
push @{ $data{stderr} } , $err_msg;

... но через шесть месяцев будет труднее понять ... 8 ^)

1 голос
/ 31 декабря 2008

выглядит хорошо. =) Улучшение, вероятно, заключается в том, чтобы закрепить эти теги в начале строки:

if (/^<parameter>:/)

Это сделает скрипт немного более устойчивым.

Вы также можете избежать удаления тега, если поймаете то, что после него и используете только эту часть:

if (/^<parameter>:(.*)/s)
{
  push @parameter, $1;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...