Как я могу извлечь строку между соответствующими фигурными скобками в Perl? - PullRequest
10 голосов
/ 23 апреля 2010

Мой входной файл, как показано ниже:

HEADER 
{ABC|*|DEF {GHI 0 1 0} {{Points {}}}}

{ABC|*|DEF {GHI 0 2 0} {{Points {}}}}

{ABC|*|XYZ:abc:def {GHI 0 22 0} {{Points {{F1 1.1} {F2 1.2} {F3 1.3} {F4 1.4}}}}}

{ABC|*|XYZ:ghi:jkl {JKL 0 372 0} {{Points {}}}}

{ABC|*|XYZ:mno:pqr {GHI 0 34 0} {{Points {}}}}

{
    ABC|*|XYZ:abc:pqr {GHI 0 68 0}
        {{Points {{F1 11.11} {F2 12.10} {F3 14.11} {F4 16.23}}}}
        }
TRAILER

Я хочу извлечь файл в массив, как показано ниже:

$array[0] = "{ABC|*|DEF {GHI 0 1 0} {{Points {}}}}"

$array[1] = "{ABC|*|DEF {GHI 0 2 0} {{Points {}}}}"

$array[2] = "{ABC|*|XYZ:abc:def {GHI 0 22 0} {{Points {{F1 1.1} {F2 1.2} {F3 1.3} {F4 1.4}}}}}"

..
..

$array[5] = "{
    ABC|*|XYZ:abc:pqr {GHI 0 68 0}
        {{Points {{F1 11.11} {F2 12.10} {F3 14.11} {F4 16.23}}}}
        }"

Это означает, что мне нужно сопоставить первую открывающую фигурную скобку с закрывающей фигурной скобкой и извлечь строку между ними.

Я проверил приведенную ниже ссылку, но это не относится к моему вопросу. Regex для получения строки между фигурными скобками "{Я хочу, что между фигурными скобками}"

Я пытаюсь, но очень помогло бы, если бы кто-то мог помочь мне с их опытом ...

Спасибо Шри ...

Ответы [ 7 ]

15 голосов
/ 23 апреля 2010
13 голосов
/ 23 апреля 2010

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

my @array = $str =~ /( \{ (?: [^{}]* | (?0) )* \} )/xg;

print join "\n" => @array;

Регулярное выражение соответствует блоку фигурных скобок, который содержит либо символы не фигурных скобок, либо рекурсию в себя (соответствует вложенным скобкам) ​​

Редактировать: приведенный выше код работает в Perl 5.10+, для более ранних версий рекурсия более многословна:

my $re; $re = qr/ \{ (?: [^{}]* | (??{$re}) )* \} /x;

my @array = $str =~ /$re/xg;
4 голосов
/ 23 апреля 2010

Я второй советую использовать модуль Text::Balanced. Несколько строк помогут вам в этом.

use strict;
use warnings;
use Text::Balanced qw/extract_multiple extract_bracketed/;

my $file;
open my $fileHandle, '<', 'file.txt';

{ 
  local $/ = undef; # or use File::Slurp
  $file = <$fileHandle>;
}

close $fileHandle;

my @array = extract_multiple(
                               $file,
                               [ sub{extract_bracketed($_[0], '{}')},],
                               undef,
                               1
                            );

print $_,"\n" foreach @array;

OUTPUT

{ABC|*|DEF {GHI 0 1 0} {{Points {}}}}
{ABC|*|DEF {GHI 0 2 0} {{Points {}}}}
{ABC|*|XYZ:abc:def {GHI 0 22 0} {{Points {{F1 1.1} {F2 1.2} {F3 1.3} {F4 1.4}}}}}
{ABC|*|XYZ:ghi:jkl {JKL 0 372 0} {{Points {}}}}
{ABC|*|XYZ:mno:pqr {GHI 0 34 0} {{Points {}}}}
{
    ABC|*|XYZ:abc:pqr {GHI 0 68 0}
        {{Points {{F1 11.11} {F2 12.10} {F3 14.11} {F4 16.23}}}}
        }
2 голосов
/ 23 апреля 2010

Вы всегда можете сосчитать фигурные скобки:

my $depth = 0;
my $out = "";
my @list=();
foreach my $fr (split(/([{}])/,$data)) {
    $out .= $fr;
    if($fr eq '{') {
        $depth ++;
    }
    elsif($fr eq '}') {
        $depth --;
        if($depth ==0) {
            $out =~ s/^.*?({.*}).*$/$1/s; # trim
            push @list, $out;
            $out = "";
        }
    }
}
print join("\n==================\n",@list);

Это старый, простой стиль Perl (и, наверное, некрасиво).

2 голосов
/ 23 апреля 2010

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

Вместо этого создайте небольшой синтаксический анализатор, аналогичный показанному здесь: http://www.perlmonks.org/?node_id=308039 (см. ответ shotgunefx (Parson) 18 ноября 2003 г. в 18:29 UTC)

ОБНОВЛЕНИЕ Кажется, что это может быть выполнимо с регулярным выражением - я видел ссылку на соответствующие вложенные скобки в Мастеринг регулярных выражений (это доступно в Google Книгах и, следовательно, может быть найдено если у вас нет книги - см. главу 5, раздел «Соответствие сбалансированным наборам скобок»)

0 голосов
/ 23 апреля 2010

Регулярные выражения на самом деле довольно плохи для сопоставления скобок. В зависимости от того, насколько глубоко вы хотите углубиться, вы можете написать полную грамматику (что намного проще, чем кажется!) Для Parse :: RecDescent . Или, если вы просто хотите получить блоки, найдите открывающие '{' отметки и закрывающие '}' и просто держите счет, сколько из них открыто в любой момент времени.

0 голосов
/ 23 апреля 2010

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

...