5

正直なところ、最初にこの質問の構文について助けを求める必要があると思います。

しかし、私が意味することを理解できる場合は、タイトルを適切なものに編集してください.

このようにテキストを分割できるパターンを作成する方法はありますか。

{{START}}
    {{START}}
        {{START}}
            {{START}}
            {{END}}
        {{END}}
    {{END}}
{{END}}

したがって、すべての {{START}} はその {{END}} に最初から最後まで一致します!

そして、正規表現のみでそれができない場合。PHPを使用してそれを行うのはどうですか?

よろしくお願いします。

4

3 に答える 3

4

これは、正規文法のみを解析できる正規表現の能力を超えています。あなたが説明していることには、プッシュダウン オートマトンが必要です (通常の言語は、通常のオートマトンによって定義されます)。

正規表現を使用して個々の要素を解析できますが、「深さ」の部分はメモリの概念を持つ言語で処理する必要があります (これには PHP が適しています)。

したがって、ソリューションでは、正規表現はタグを識別するためにのみ使用されますが、深さを追跡し、END タグが属する要素を決定するための実際のロジックは、プログラム自体である必要があります。

于 2013-06-22T04:18:58.800 に答える
3

可能です!再帰的な正規表現を使用して、各レベルのコンテンツを作成できます。

$data = <<<LOD
{{START1}}
    aaaaa
    {{START2}}
        bbbbb
        {{START3}}
            ccccc
            {{START4}}
                ddddd
            {{END4}}
        {{END3}}
    {{END2}}
{{END1}}
LOD;

$pattern = '~(?=({{START\d+}}(?>[^{]++|(?1))*{{END\d+}}))~';
preg_match_all ($pattern, $data, $matches);

print_r($matches);

説明:

部:({{START\d+}}(?>[^{]++|(?1))*{{END\d+}})

パターンのこの部分は、ネストされた構造を記述し{{START#}}{{END#}}

(             # open the first capturing group
{{START\d+}}  
(?>           # open an atomic group (= backtracks forbidden)
    [^{]++    # all that is not a { one or more times (possessive)
  |           # OR
    (?1)      # refer to the first capturing group itself
)             # close the atomic group
{END\d+}}     # 
)             # close the first capturing group

問題は、文字列のすべての文字がパターンによって消費されるため、この部分だけですべてのレベルをキャプチャできないことです。つまり、文字列の重複部分を一致させることはできません。

問題は、この部分をすべて、 lookahead のような文字を消費しないゼロ幅アサーション内にラップする(?=...)ことです。結果:

(?=({{START\d+}}(?>[^{]++|(?1))*{{END\d+}}))

これはすべてのレベルに一致します。

于 2013-06-22T04:56:16.297 に答える
1

純粋な RegEx ではこれを行うことはできませんが、単純なループでは実現できます。

JS の例:

//[.\s\S]* ensures line breaks are matched (dotall not supported in JS)
var exp = /\{\{START\}\}([.\s\S]*)\{\{END\}\}/;

var myString = "{{START}}\ntest\n{{START}}\ntest 2\n{{START}}\ntest 3\n{{START}}\ntest4\n{{END}}\n{{END}}\n{{END}}\n{{END}}";

var matches = [];
var m = exp.exec(myString);
while ( m != null ) {
    matches.push(m[0]);
    m = exp.exec(m[1]);
}

alert(matches.join("\n\n"));

PHP (これが正しいかどうかはわかりません。PHP を使用してからずっと経ちます)

$pattern = "/\{\{START\}\}([.\s\S]*)\{\{END\}\}/";
$myString = "{{START}}\ntest\n{{START}}\ntest 2\n{{START}}\ntest 3\n{{START}}\ntest4\n{{END}}\n{{END}}\n{{END}}\n{{END}}";

$result = preg_match($pattern, $myString, $matches, PREG_OFFSET_CAPTURE);
$outMatches = array();
while ( $result ) {
    array_push($outMatches, $matches[0]);
    $result = preg_match($pattern, $matches[1], $matches, PREG_OFFSET_CAPTURE);
}
print($outMatches);

出力:

{{START}}
test
{{START}}
test 2
{{START}}
test 3
{{START}}
test4
{{END}}
{{END}}
{{END}}
{{END}}

{{START}}
test 2
{{START}}
test 3
{{START}}
test4
{{END}}
{{END}}
{{END}}

{{START}}
test 3
{{START}}
test4
{{END}}
{{END}}

{{START}}
test4
{{END}} 
于 2013-06-22T04:46:42.417 に答える