Finding matching brackets with php / regex in longer texts

I tried to wrap my head for a long time, but still have not found a solution.

I'm working on some simple formatting method where I need tags containing strings inside brackets, with a tag defined immediately before the bracket. Tags must also be inside other brackets.

String

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

What I want to do now is the content of each

 tag1{} tag2{} tag3{} 

I found others with similar problems ( Find matching brackets using a regular expression ), but their problem was more focused on how to find matching brackets inside other brackets, while my problem was that finding multiple brackets in more long text.

+4
source share
4 answers

If the tags are always balanced, you can use an expression like this to get the contents and name of all tags, including nested tags.

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

An 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]); 

Output:

 * 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 ) 
+3
source

I don’t know if there is a regular expression that receives all internal and external tags in one call, but you can use this regular expression /\{(([^\{\}]+)|(?R))*\}/ from a question related to you and iterate over the results recursively.

I added your tag name and some sub-elements in regexp for clarity:

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

Returns an array with all matches containing the entire match, the tag name, the contents of the brackets, and an iteration counter, showing how often the match was nested inside other tags. I added one more level of nesting of your line for demonstration:

 $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>'; 

The output will be:

 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 ) ) 
+2
source

this is regex:

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

and you must first replace the internal tags

+1
source

I think there is no other way. You need to flip each bracket.

  $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); } 
0
source

Source: https://habr.com/ru/post/1394575/


All Articles