Соответствующие сбалансированные скобки в регулярном выражении Perl

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

aaa="bbb{ccc}ddd" { aa="bb,cc" { a="b", c="d" } }, aaa="bbb{}" { aa="b}b" }, aaa="bbb,ccc"

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

aaa="bbb{ccc}ddd" { aa="bb,cc" { a="b", c="d" } }
aaa="bbb{}" { aa="b}b" }
aaa="bbb,ccc"

Я использую Perl версии 5.8 и кто-то может решить эту проблему?

7 ответов

Используйте модуль perl "Regexp::Common". У этого есть хорошая сбалансированная скобка Regex, которая работает хорошо.

# ASN.1
use Regexp::Common;
$bp = $RE{balanced}{-parens=>'{}'};
@genes = $l =~ /($bp)/g;

В Perlre есть пример использования рекурсивных функций регулярных выражений, представленных в v5.10. Хотя вы ограничены версией v8.8, другие люди, приходящие на этот вопрос, должны найти правильное решение:)

$re = qr{ 
            (                                # paren group 1 (full function)
                foo
                (                            # paren group 2 (parens)
                    \(
                        (                    # paren group 3 (contents of parens)
                            (?:
                                (?> [^()]+ ) # Non-parens without backtracking
                                |
                                (?2)         # Recurse to start of paren group 2
                            )*
                        )
                    \)
                )
            )
    }x;

Чтобы соответствовать сбалансированным круглым скобкам или фигурным скобкам, и если вы хотите учесть обратные косые (экранированные) скобки, предлагаемые решения не будут работать. Вместо этого вы должны написать что-то вроде этого (основываясь на предложенном решении на perlre ):

      $re = qr/
(                                                # paren group 1 (full function)
    foo
    (?<paren_group>                              # paren group 2 (parens)
        \(
            (                                    # paren group 3 (contents of parens)
                (?:
                    (?> (?:\\[()]|(?![()]).)+ )  # escaped parens or no parens
                    |
                    (?&paren_group)              # Recurse to named capture group
                )*
            )
        \)
    )
)
/x;

Попробуйте что-то вроде этого:

use strict;
use warnings;
use Data::Dumper;

my $exp=<<END;
aaa="bbb{ccc}ddd" { aa="bb,cc" { a="b", c="d" } }     , aaa="bbb{}" { aa="b}b" }, aaa="bbb,ccc"
END

chomp $exp;
my @arr = map { $_ =~ s/^\s*//; $_ =~ s/\s* $//; "$_}"} split('}\s*,',$exp);
print Dumper(\@arr);

Я согласен со Скоттом Риппи, более или менее, написать собственный парсер. Вот простой:

my $in = 'aaa="bbb{ccc}ddd" { aa="bb,cc" { a="b", c="d" } }, ' .
         'aaa="bbb{}" { aa="b}b" }, ' .
         'aaa="bbb,ccc"'
;

my @out = ('');

my $nesting = 0;
while($in !~ m/\G$/cg)
{
  if($nesting == 0 && $in =~ m/\G,\s*/cg)
  {
    push @out, '';
    next;
  }
  if($in =~ m/\G(\{+)/cg)
    { $nesting += length $1; }
  elsif($in =~ m/\G(\}+)/cg)
  {
    $nesting -= length $1;
    die if $nesting < 0;
  }
  elsif($in =~ m/\G((?:[^{}"]|"[^"]*")+)/cg)
    { }
  else
    { die; }
  $out[-1] .= $1;
}

(Протестировано в Perl 5.10; извините, у меня нет Perl 5.8 под рукой, но, насколько я знаю, нет никаких существенных различий.) Излишне говорить, что вы захотите заменить dieс чем-то конкретным приложением. И вам, вероятно, придется настроить вышеупомянутое для обработки случаев, не включенных в ваш пример. (Например, могут ли строки в кавычках содержать \"? Можно ' использоваться вместо "? Этот код не обрабатывает ни одну из этих возможностей.)

Расколотое решение кажется самым простым. Разделить взгляд на вашу основную переменную aaa, с границей слова вокруг. Удалите конечные пробелы и запятую с необязательной группой символов.

$string = 'aaa="bbb{ccc}ddd" { aa="bb,cc" { a="b", c="d" } }, aaa="bbb{}" { aa="b}b" }, aaa="bbb,ccc"';
my @array = split /[,\s]*(?=\baaa\b)/, $string;

Хотя рекурсивные регулярные выражения обычно можно использовать для захвата "сбалансированных скобок" {}, они не будут работать на вас, потому что вы также должны соответствовать "сбалансированным кавычкам" ",
Это было бы очень сложной задачей для регулярного выражения Perl, и я вполне уверен, что это невозможно. (В отличие от этого, вероятно, это можно сделать с помощью функции регулярных выражений Microsoft "балансировки групп").

Я бы предложил создать свой собственный парсер. Когда вы обрабатываете каждого персонажа, вы считаете каждого " а также {}и только разделить на , если они "сбалансированы".

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