2012-02-03 10 views
4

私はかなり長い間、これを頭の中に入れようとしましたが、解決策はまだ見つかりませんでした。長いテキストでphp/regexと一致する括弧を見つける

私はいくつかの簡単な書式設定に取り組んでいます。ここでは、ブラケットの前にタグが定義された、括弧内に文字列を含むタグが必要です。タグは他の括弧の中に入れることもできます。

文字列:

This is some random text, tag1{while this is inside a tag2{tag}}. This is some 
other text tag2{also with a tag tag3{inside} of it}. 

私は今、何をしたいのかは、私は同様の問題(Find matching brackets using regular expression)と他の人を見つけたが、その問題はもっと上に配向された各

tag1{} 
tag2{} 
tag3{} 

の内容ですどのように他の括弧の中に一致する括弧を見つけるか、私の問題はその両方であり、長い括弧の中に複数の括弧を見つけることです。

答えて

1

正規表現は、このです:

tag[0-9]+\{[^\}]+ 

、あなたが最初に内部タグを置き換える必要があります

私は知らない
2

、であなたのすべての内側と外側のタグを取得する正規表現がある場合1つの呼び出しですが、リンクした質問のこの正規表現/\{(([^\{\}]+)|(?R))*\}/を使用して、結果に再帰的に反復することができます。

私はより明確にするための正規表現に自分のタグ名と、いくつかの名前のサブパターンを追加しました:

function search_tags($string, $recursion = 0) { 
    $Results = array(); 
    if (preg_match_all("/(?<tagname>[\w]+)\{(?<content>(([^\{\}]+)|(?R))*)\}/", $string, $matches, PREG_SET_ORDER)) { 
     foreach ($matches as $match) { 
      $Results[] = array('match' => $match[0], 'tagname' => $match['tagname'], 'content' => $match['content'], 'deepness' => $recursion); 
      if ($InnerResults = search_tags($match['content'], $recursion+1)) { 
       $Results = array_merge($Results, $InnerResults); 
      } 
     } 
     return $Results; 
    } 
    return false; 
} 

これは、全体の一致を含むすべての一致、タグ名、括弧の内容を持つ配列を返し、 反復カウンタで、他のタグの中でどのくらいの頻度でネストされたかを表示します。私はデモのためにあなたの文字列にネストの別のレベルを追加しました:

$text = "This is some random text, tag1{while this is inside a tag2{tag}}. This is some other text tag3{also with a tag tag4{and another nested tag5{inside}} of it}."; 
echo '<pre>'.print_r(search_tags($text), true).'</pre>'; 

出力は次のようになります。

Array 
(
    [0] => Array 
     (
      [match] => tag1{while this is inside a tag2{tag}} 
      [tagname] => tag1 
      [content] => while this is inside a tag2{tag} 
      [deepness] => 0 
     ) 

    [1] => Array 
     (
      [match] => tag2{tag} 
      [tagname] => tag2 
      [content] => tag 
      [deepness] => 1 
     ) 

    [2] => Array 
     (
      [match] => tag3{also with a tag tag4{and another nested tag5{inside}} of it} 
      [tagname] => tag3 
      [content] => also with a tag tag4{and another nested tag5{inside}} of it 
      [deepness] => 0 
     ) 

    [3] => Array 
     (
      [match] => tag4{and another nested tag5{inside}} 
      [tagname] => tag4 
      [content] => and another nested tag5{inside} 
      [deepness] => 1 
     ) 

    [4] => Array 
     (
      [match] => tag5{inside} 
      [tagname] => tag5 
      [content] => inside 
      [deepness] => 2 
     ) 

) 
3

タグは常に平衡している場合は、コンテンツを取得するには、このような表現を使用することができますし、ネストされたタグを含むすべてのタグの名前。

\b(\w+)(?={((?:[^{}]+|{(?2)})*)}) 

Example

$str = "This is some random text, tag1{while this is inside a tag2{tag}}. This is some other text tag2{also with a tag tag3{inside} of it}."; 

$re = "/\\b(\\w+)(?={((?:[^{}]+|{(?2)})*)})/"; 
preg_match_all($re, $str, $m); 

echo "* Tag names:\n"; 
print_r($m[1]); 
echo "* Tag content:\n"; 
print_r($m[2]); 

出力:

* Tag names: 
Array 
(
    [0] => tag1 
    [1] => tag2 
    [2] => tag2 
    [3] => tag3 
) 
* Tag content: 
Array 
(
    [0] => while this is inside a tag2{tag} 
    [1] => tag 
    [2] => also with a tag tag3{inside} of it 
    [3] => inside 
) 
+2

+1は再帰的サブパターンです。 – cmbuckley

+0

@cbuckley、どちらも元の表現が動作します。最初のオリジナルのものは、より短く、より良いですが、キャプチャでは '{}'を取り囲んでいます。 – Qtax

+0

合意。私はちょうど正規表現とその一貫した例を作っていた。私の変更を元に戻すか、両方の正規表現に言及するように編集してください。 – cmbuckley

0

私は他の方法がないと思います。各ブラケットをループする必要があります。

 $output=array(); 
    $pos=0;  
while(preg_match('/tag\d+\{/S',$input,$match,PREG_OFFSET_CAPTURE,$pos)){ 
    $start=$match[0][1]; 
    $pos=$offset=$start+strlen($match[0][0]); 
    $bracket=1; 
    while($bracket!==0 and preg_match('/\{|\}/S',$input,$found,PREG_OFFSET_CAPTURE,$offset)){ 
     ($found[0][0]==='}')?$bracket--:$bracket++; 
     $offset=$found[0][1]+1; 
    } 
    $output[]=substr($input,$start,$offset-$start); 
}   
関連する問題