12

私の入力ファイルは以下の通りです:

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

つまり、最初の開始中括弧をその終了中括弧と一致させ、その間の文字列を抽出する必要があります。

以下のリンクを確認しましたが、これは私の質問には当てはまりません。 中括弧の間に文字列を取得する正規表現「{中括弧の間にあるものが欲しい}」

私は努力していますが、誰かが彼らの専門知識で私を助けてくれるなら本当に助けになるでしょう...

ありがとうスリ...

4

7 に答える 7

15

Text::Balancedを使用する

于 2010-04-23T17:35:28.220 に答える
15

これは確かに、少なくとも最新バージョンのPerlでは正規表現を使用して実行できます。

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

print join "\n" => @array;

正規表現は、中括弧以外の文字、またはそれ自体への再帰(ネストされた中括弧に一致)のいずれかを含む中括弧ブロックに一致します

編集:上記のコードはPerl 5.10以降で機能します。以前のバージョンでは、再帰はもう少し冗長です。

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

my @array = $str =~ /$re/xg;
于 2010-04-23T17:44:25.723 に答える
4

モジュールを使用するための2番目のysthの提案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;

出力

{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}}}}
        }
于 2010-04-23T18:21:07.683 に答える
2

ここで使用したいのは純粋な正規表現ではないと思います(私見では、これは正規表現を使用しても解析できない可能性があります)。

代わりに、ここに示されているもののような小さなパーサーを作成します:http: //www.perlmonks.org/? node_id=308039(2003年11月18日18:29 UTCのshotgunefx(Parson)による回答を参照)

更新正規表現で実行できるようです-正規表現のマスターでネストされた括弧の一致への参照を見ました(これはGoogleブックスで利用できるため、本がない場合はグーグルで検索できます-第5章のセクション「」を参照してください。括弧のバランスの取れたセットの一致」)

于 2010-04-23T17:33:28.497 に答える
2

中かっこはいつでも数えることができます。

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スタイルです(そしておそらく醜いです)。

于 2010-04-23T17:56:17.033 に答える
0

このタイプの構文解析には、正規表現よりもステートマシンを使用する方がはるかに優れています。

于 2010-04-23T17:29:51.080 に答える
0

正規表現は、実際には中括弧のマッチングにはかなり適していません。どれだけ深く行きたいかに応じて、Parse :: RecDescentの完全な文法を書くことができます(これは思ったよりもはるかに簡単です!) 。または、ブロックを取得したいだけの場合は、開始'{'マークと終了'}'を検索し、任意の時点で開いている数を数えます。

于 2010-04-23T17:34:21.907 に答える