Соответствующие сбалансированные скобки в регулярном выражении Perl - PullRequest
6 голосов
/ 02 ноября 2011

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

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, и кто-нибудь может решить эту проблему?

Ответы [ 6 ]

9 голосов
/ 22 августа 2012

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

# ASN.1
use Regexp::Common;
$bp = $RE{balanced}{-parens=>'{}'};
@genes = $l =~ /($bp)/g;
7 голосов
/ 01 октября 2013

В 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;
1 голос
/ 02 ноября 2011

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

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 на что-то конкретное для приложения.И вам, вероятно, придется настроить вышеупомянутое для обработки случаев, не включенных в ваш пример.(Например, могут ли строки в кавычках содержать \"? Может ли использоваться ' вместо "? Этот код не обрабатывает ни одну из этих возможностей.)

1 голос
/ 02 ноября 2011

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

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);
0 голосов
/ 02 ноября 2011

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

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

0 голосов
/ 02 ноября 2011

Разделенное решение кажется самым простым.Разделить взгляд на вашу основную переменную 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;
...