Разбор неправильных текстовых файлов в Perl - PullRequest
3 голосов
/ 20 мая 2011

Я новичок в программировании на Perl и хотел бы узнать о синтаксическом анализе текстовых файлов с помощью Perl. У меня есть текстовый файл с неправильным форматированием, и я хотел бы разбить его на три части.

В основном файл содержит текст, подобный следующему:

;out;asoljefsaiouerfas'pozsirt'z
mysql_query("SELECT * FROM Table WHERE (value='true') OR (value2='true') OR (value3='true') ");
1234 434 3454

4if[9put[e]9sd=09q]024s-q]3-=04i
select ta.somefield, tc.somefield 
from TableA ta INNER JOIN TableC tc on tc.somefield=ta.somefield 
INNER JOIN TableB tb on tb.somefield=ta.somefield 
ORDER by tb.somefield
234 4536 234

и список можно продолжить в этом формате.

Итак, мне нужно разобрать это за три. А именно тот, что наверху, получающий хеш-чеки. Второй запрос mysql, третий - анализ трех чисел. Почему-то я не понимаю, как это сделать. Я использую функцию «открыть» в Perl, чтобы получить данные из текстового файла. А затем я пытаюсь использовать функцию «split» для разрывов строк, но оказывается, что запросы не находятся ни в одной строке, ни в шаблоне, поэтому я не могу использовать это таким образом, как я понял.

Ответы [ 3 ]

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

Допущения:

  1. Между порциями данных будет пустая строка.
  2. Эта пустая строка будет состоять только из новой строки.
  3. В этих чанках проверки хеша будут верхней единственной строкой, а три числа будут нижней одна строка.

с учетом этого:

use strict;
use warnings;
use English qw<$RS $OS_ERROR>;

local $RS = "\n\n";

open( my $fh, '<', $path_to_file ) 
    or die "Could not open $path_to_file! - $OS_ERROR"
    ;
while ( <> ) { 
    chomp;
    my ( $hash_check_line
       , @inner_lines 
       )
       = split /\n/
       ;
    my @numbers = split /\D+/, pop @inner_lines;
    my $sql     = join( "\n", @inner_lines );

    ...
}

Путем изменения $RS ($/ или $INPUT_RECORD_SEPARATOR) чтобы удвоить переводы строки, мы изменим способ чтения записей.

Это не так странно, но в годы работы с Perl мне приходилось делать разделитель записей довольно интересными строками, но иногда это всетребуется только чтение фрагмента, который вы хотите прочитать.

3 голосов
/ 20 мая 2011

О, Боже.

Алгоритм, который я вижу:

  • Кэшируйте первую строку.
  • Читать все строки до пустой строки.
  • 'Последняя' строка будет цифрами.
  • Все остальное будет запросом.

Имея это в виду, я представляю следующий код:

open my $fh, '<', $path_to_file
    or die "Can't open $path_to_file: $!";
while (my ($checksum, $query, $numbers) = read_record($fh) ) {
    # do something with record
}
close $fh or warn "$!";

sub read_record {
    my $fh = shift;
    my @lines;
    LINE: while (my $line = <$fh>) {
        chomp $line;
        last LINE if $line eq q{}; # if empty, we're done with the record!
        push @lines, $line;        # store it :)
    }
    return unless @lines;          # if we didn't get anything, eof!
    my $checksum = shift @lines;   # first was checksum.
    my $numbers = pop @lines;      # last thing read was numbers.
    my $query = join ' ', @lines;  # everything else, query.
    return ($checksum, $query, $numbers);
}

Измените, конечно, в соответствии с граничными условиями.

2 голосов
/ 20 мая 2011

Кажется, работает следующее:

while ($file_content =~ /\s*^(.+?)^(.*?)^(\d+\s+\d+\s+\d+)$/smg) {
    my $checksum = $1;
    my $query = $2;
    my $numbers = $3;
    # do stuff
}

Вот объяснение регулярному выражению:

\s*                   # eat up empty lines
^(.+?)                # save the checksum line to group 1
^(.+?)                # save one or multiple query lines to group 2
^(\d+\s+\d+\s+\d+)$   # save number line to group 3

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

...