Ответ 1
Используйте модуль perl "Regexp:: Common". Он имеет хорошее сбалансированное регулярное выражение, которое хорошо работает.
# ASN.1
use Regexp::Common;
$bp = $RE{balanced}{-parens=>'{}'};
@genes = $l =~ /($bp)/g;
У меня есть выражение, которое мне нужно разбить и сохранить в массиве:
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 и может ли кто-то решить эту проблему?
Используйте модуль perl "Regexp:: Common". Он имеет хорошее сбалансированное регулярное выражение, которое хорошо работает.
# ASN.1
use Regexp::Common;
$bp = $RE{balanced}{-parens=>'{}'};
@genes = $l =~ /($bp)/g;
Вот пример в perlre, используя рекурсивные функции регулярного выражения, представленные в версии 5.10. Хотя вы ограничены v5.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;
Попробуйте что-то вроде этого:
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
на что-то конкретное приложение. И вам, вероятно, придется подстроить выше, чтобы обрабатывать случаи, не включенные в ваш пример. (Например, могут ли строки с кавычками содержать \"
? Может ли '
использоваться вместо "
? Этот код не обрабатывает ни одну из этих возможностей.)
Хотя Рекурсивные регулярные выражения обычно можно использовать для захвата "сбалансированных фигурных скобок" {}
, они не будут работать для вас, потому что у вас также есть требование соответствовать "сбалансированным котировкам" "
.
Это было бы очень сложной задачей для регулярного выражения Perl, и я уверен, что это невозможно. (Напротив, это можно было бы сделать с помощью функции балансировки групп Microsoft" Regex).
Я бы предложил создать собственный парсер. Когда вы обрабатываете каждый символ, вы считаете каждый "
и {}
и разделяете только на ,
, если они "сбалансированы".
Расколотое решение кажется простым. Разделите взгляд на свою основную переменную 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;