2011-11-01 20 views
4

でバランスの取れた括弧のマッチング私は、配列に分割して保存する必要がある表現があります。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を使用していますが、誰かがこれを解決できましたか?

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

あなたはちょうど分割しません。 – FailedDev

+2

@FailedDev恐らく分割されたくない '、'のためにおそらく分割されています。 –

+0

@ScottRippeyここで盲目的であると話してください:) – FailedDev

答えて

1

はこのような何かを試してみてください。主な変数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; 
+0

ありがとうございます。私はそれが 'aa =" bb}、cc "'のようなものにマッチしたときに壊れていることを発見しました。 – meharo

-1

スプリット・ソリューションは、最も単純なようだ:

+0

これは私が使用したダミーデータの問題でした。実際のシナリオでははるかに複雑です。 – meharo

+0

@ meharoそして問題は...? – TLP

+0

'aaa'または類似のパターンが最初に常に表示されないことがあります。私は 'aaa =" bbb {} "{aa =" b} b "}、zzz =" bbb、ccc "' – meharo

0

Recursive Regular Expressionsは通常、「バランスの取れた括弧」{}を捕捉するために使用することができますが、あなたも「バランスの取れた引用符」"と一致する必要があるため、彼らはあなたのために動作しません。
これはPerlの正規表現にとって非常に難しい作業ですが、私はそれが不可能であることは確かです。 (対照的に、これは恐らくMicrosoft's "balancing groups" Regex featureで行うことができます)。

独自のパーサーを作成することをお勧めします。それぞれのキャラクターを処理するときには、それぞれ"{}とカウントされ、「平衡」の場合は,に分割されます。

+1

私はそれがPerlでできると思います。特に新しいPerlプログラマーに。 [Regexp :: Grammars](http://search.cpan.org/perldoc/Regexp::Grammars)スタイルの正規表現を使用する方が簡単かもしれませんが。 **本当の**パーサを使うと、おそらく[Marpa](http://search.cpan.org/dist/Marpa/)がうまくいくでしょう。 –

+0

[Regexp :: Grammars](http://search.cpan.org/perldoc/Regexp::Grammars)は5.8ではサポートされていません:( – meharo

+0

非常に可能ですが、何かをお勧めしません:) –

1

私は、自分のパーサーを書くことについて、多かれ少なかれScott Rippeyに同意します。ここでは単純なものです:

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; 
} 

(5.10でテスト;申し訳ありませんが、私はPerlの5.8が手元にないが、これまでのところ、私は知っているように関連するすべての違いがありません。)言うまでもなく、あなたは」 dieをアプリケーション固有のものに置き換えてください。そして、あなたの例に含まれていないケースを扱うために上記を調整する必要があるでしょう。 (引用符で囲まれた文字列が'代わり"の使用することはできますか?\"を含めることができますたとえば、?このコードは、これらの可能性のいずれかを処理しません。)

+0

私は、私の答えはPerlのスピーカーが私の答えに同意していることを知ってうれしく思いました。私はPCREだけを話すので、パーサーは不可能なRegexよりも簡単であるという大胆な前提がありました。 –

+0

ここではPerl5バージョン8で同じことをすることができないようなことはありません –

7

のPerlモジュール「正規表現::一般的な」を使用します。それはうまく動作する良いバランスのとれた括弧Regexを持っています。

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

例はV5.10で導入された再帰的な正規表現の機能を使用して、perlreにあります。あなたは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;