PHP,preg_match:如何在两个字符之间获取字符串,如花括号,其中子标记用花括号括起来?

时间:2014-05-11 20:01:18

标签: php preg-match preg-match-all templating

如果我有如下字符串:

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

...我想得到以下结果:

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

我已经有了这个功能,但我相信可以用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;
}

我尝试过以下方法,但它与次级标记的效果不佳。

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',
)

是否有可能调整上述模式以获得正确的结果?

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

1 个答案:

答案 0 :(得分:1)

您需要使用递归模式,例如:

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

(?R)代表所有模式(整个模式在其内部重复)