3

PHPを使用してネストされたブレース内に入る方法は?

例:

{{ text1 {{text2 text3 {{text4}} text5}} }}

出力する必要があります

1- text1 {{text2 text3 {{text4}} text5}}
2- text2 text3 {{text4}} text5
3- text4
4

3 に答える 3

5

これには括弧の数を追跡する必要があり、正規表現を使用して行うことはできません。これには、独自のパーサー ロジックを作成する必要があります。正規表現はパーサーではありません。申し訳ありません。

ここに私のものと同じ応答を持つ別の同様の質問があります

そして、これはパースの構築に関するSOです(Javaで、しかし十分に翻訳する必要があります)

于 2012-07-02T12:59:27.500 に答える
2

PCRE は、Perl と同様に、ネストされた構造を任意の深さに一致させることができます (メモリによってのみ制限されます - 以下を参照)。テスト済みのスクリプトは次のとおりです。

ネストされたブラケットに一致する正規表現

<?php // test.php Rev:20120702_1100

$re_nested_double_bracket ='% # Rev:20120702_1100
    # Match {{...{{...}}...}} structure with arbitrary nesting.
    \{\{                      # Opening literal double bracket.
    (                         # $1: Contents of double brackets.
      (?:                     # Group for contents alternatives.
        [^{}]++               # Either one or more non-brackets,
      | (?R)                  # or a nested bracket pair,
      | \{                    # or the start of opening bracket
        (?!\{)                # (if not a complete open bracket),
      | \}                    # or the start of closing bracket.
        (?!\})                # (if not a complete close bracket).
      )*                      # Zero or more contents alternatives.
    )                         # End $1: Contents of double brackets.
    \}\}                      # Closing literal double bracket.
    %x';

$results = array(); // Global array to receive results.

// Recursively called callback routine adds to $results array.
function _bracket_contents_callback($matches) {
    global $results, $re_nested_double_bracket;
    $results[] = $matches[1];
    preg_replace_callback($re_nested_double_bracket,
        '_bracket_contents_callback', $matches[1]);
    return $matches[0]; // Don't modify string.
}

$input = file_get_contents('testdata.txt');
preg_replace_callback($re_nested_double_bracket,
    '_bracket_contents_callback', $input);

$count = count($results);
printf("There were %d matches found.\n", $count);
for ($i = 0; $i < $count; ++$i) {
    printf("  Match[%d]: %s\n", $i + 1, $results[$i]);
}
?>

元の投稿のテスト データに対して実行すると、正規表現が一致するものが次のようになります。

出力例:

There were 3 matches found.
Match[1]: text1 {{text2 text3 {{text4}} text5}}
Match[2]: text2 text3 {{text4}} text5
Match[3]: text4

この正規表現は、ネストされている可能性のあるブラケットの最も外側$1のセットと一致し、ブラケット間のコンテンツをグループにキャプチャすることに注意してください。このスクリプトはpreg_replace_callback()関数を使用して、ネストされたブラケットの内容を再帰的に照合し、結果配列に追加します。

「任意の深さ」このソリューションは、ネストされたブラケットを「任意の深さ」に一致させますが、常にシステム メモリ、実行可能スタック サイズと PHP pcre.backtrack_limitpcre.recursion_limitおよびmemory_limit構成変数によって制限されることに注意してください。件名の文字列が大きすぎる場合や、特定のホスト システムに対してネストが深すぎる場合、この正規表現ソリューションが失敗する可能性があることに注意してください。PHP/PCRE ライブラリが、実行中の実行可能ファイルにスタック オーバーフロー、セグメンテーション違反、およびプログラム クラッシュを引き起こす可能性さえあります。これがどのように、なぜ発生するのか (およびそれを回避し、この種のエラーを適切に処理する方法) についての詳細な説明については、関連する質問に対する私の回答を参照してください: RegExp in preg_match function return browser error and PHP 正規表現: このコードに問題はありますか? .

注: この質問 (および私の回答) は、正規表現を使用した独自のタグ構文の解析 - ネストされたタグを検出する方法とほぼ同じです。、しかしこの回答では、ネストされたすべてのブラケットの内容を再帰的に照合して保存する、より完全なソリューションが提示されています。

于 2012-07-02T14:35:02.057 に答える
0

私が探していた答えを見つけて、これをここに置いて、誰もが使用できるようにしました。その非常に単純な、1 行のみ:

  $text1=preg_replace("/\{\{(([^{}]*|(?R))*)\}\}/",'',$text1);

すべての {{text}} を検索して、必要なものに置き換えます。preg_match_all を使用して、配列内のすべてを取得することもできます。

于 2012-07-07T07:31:59.830 に答える