Разбор файла журнала с использованием perl - PullRequest
1 голос
/ 12 мая 2011

У меня есть файл журнала, в котором некоторые записи выглядят так:

YY/MM/DD HH:MM:SS:MMM <Some constant text> v1=XXX v2=YYY v3=ZZZ v4=AAA AND BBB v5=CCC

, и я пытаюсь перевести его в формат CSV:

Date,Time,v1,v2,v3,v4,v5
YY/MM/DD,HH:MM:SS:MMM,XXX,YYY,ZZZ,AAA AND BBB,CCC

I 'Я хотел бы сделать это на Perl - говоря лично, я, вероятно, мог бы сделать это намного быстрее на других языках, но я действительно хотел бы немного расширить свой кругозор.

До сих пор я могу достичь даже чтениявведите и выделите только те строки, которые соответствуют моим критериям, но я не могу выполнить следующий этап.Мне нужно разделить строку ввода, но пока я просто не могу понять, как это сделать.Я посмотрел на s// и m//, но они не дают мне то, что я хочу.Если кто-то может посоветовать мне, как это можно сделать или дать мне подсказки, я буду очень признателен.

Важные моменты:

  • Значения во второмчасть строки всегда в одном и том же порядке, поэтому отображение / реорганизация не обязательно являются проблемой.
  • В некоторых полях есть свободный текст, который не заключен в кавычки :( но все метки начинаются с v<number>=Я надеюсь, что разбор все еще возможен.

Ответы [ 3 ]

6 голосов
/ 12 мая 2011

Поскольку разделителя нет, вам нужно попробовать это несколькими способами:

Сначала разделите на ' ', затем примите первые три значения:

my @array = split / /, $line;
my ($date, $time, $constant) = splice @array, 0, 3;

Снова объедините остальные поля и заново разделите на v\d+=, чтобы получить значения:

my $rest = join ' ', @array;

# $rest should now be "v1=XXX v2=YYY ..."
my @values = split /\s*v\d+=/, $rest;
shift @values; # since the first element in @values will be empty

print join ',', $date, $time, @values;

Редактировать : Вот еще один подход, которому легче следовать, и он немного более эффективен. Это использует тот факт, что ваш постоянный текст находится между датой / временем и списком значений.

# assume that CONSTANT is your constant text
my ($datetime, $valuelist) = split /\s*CONSTANT\s*/, $line;
my ($date, $time) = split / /, $datetime;
my @values = split /\s*v\d+=/, $valuelist;
shift @values;

print join ',', $date, $time, @values, "\n";
4 голосов
/ 12 мая 2011

Что вы пробовали с регулярными выражениями и как это не сработало?Регулярное выражение с m// прекрасно работает для меня:

#!/usr/bin/env perl

use strict;
use warnings;

print "Date,Time,v1,v2,v3,v4,v5\n";

while (my $line = <DATA>) {
    my @matched = $line =~ m{^([^ ]+) ([^ ]+).*v1=(.*) v2=(.*) v3=(.*) v4=(.*) v5=(.*)};
    print join(',', @matched), "\n";
}

__DATA__
YY/MM/DD HH:MM:SS:MMM <Some constant text> v1=XXX v2=YYY v3=ZZZ v4=AAA AND BBB v5=CCC

Два предостережения:

1) v1 не может содержать подстроку "v2 =", v2 не может содержать "v3 =" и т. Д.., но в таком свободном формате это может вызвать проблемы у человека, пытающегося его проанализировать.

2) В этом коде предполагается, что всегда будут версии от v1 до v5.Если в поле меньше пяти v * n *, строка не будет соответствовать.Если их больше, все дополнительные поля будут добавлены в v5 (включая их теги v * n *).

1 голос
/ 13 мая 2011

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

...