PHP, preg_match: How to get strings in between two chars like curly braces with sub markers wraped in curly braces inside?

StackOverflow https://stackoverflow.com/questions/23597289

Domanda

If I have a string like below:

$str = "Some {translate:text} with some {if:{isCool}?{translate:cool}|{translate:uncool}} features";

... I would like to get the following result:

array (
  0 => 'translate:text',
  1 => 'if:{isCool}?{translate:cool}|{translate:uncool}',
)

I already have this function but i belive its possible to simplify it with preg_match(_all)?

define('STR_START','{');
define('STR_END','}');

function getMarkers($str, &$arr = array()) {
    if(strpos($str,STR_START)) {
        list($trash,$str) = explode(STR_START,$str, 2);
        unset($trash);

        $startPos = 0;
        $endPos = 0;
        do {
            $strStartPos = strpos($str,STR_START,$startPos);
            $strEndPos = strpos($str,STR_END,$endPos);
            $startPos = $strStartPos + 1;
            $endPos = $strEndPos + 1;
        } while($strStartPos !== false && $strStartPos < $strEndPos);

        $arr[] = substr($str,0,$strEndPos);
        getMarkers(substr($str,$strEndPos+1),$arr);
    }
    return $arr;
}

I have tried the following but it dose not work that well with submarkers.

preg_match_all('/\{(.*?)\}/',"Some {translate:text} with some {if:{isCool}?{translate:cool}|{translate:uncool}} features", $matches);
var_export($matches[1]);

array (
  0 => 'translate:text',
  1 => 'if:{isCool',
  2 => 'translate:cool',
  3 => 'translate:uncool',
)

Is it possible to ajust the abowe mentioned pattern to get the right result?

array (
  0 => 'translate:text',
  1 => 'if:{isCool}?{translate:cool}|{translate:uncool}',
)
È stato utile?

Soluzione

You need to use a recursive pattern, example:

$pattern = '~{((?>[^{}]++|(?R))*)}~';

Where (?R) stands for all the pattern (the whole pattern repeated inside itself)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top