需要递归正则表达式帮助

时间:2012-10-16 20:47:09

标签: php regex recursion

我正在制作一个模板系统,我可以输入:

<t:category:item:parameter1:parameter2...>

并将其替换为文件中的文本。可选参数作为%1%2 ...

放置在替换字符串中

到目前为止,我有这个:

$data = preg_replace_callback("/<t:([^:]+):([^>]+)>/",function($m) use (&$userdata) {
    static $fcache = Array();
    $parse = function($file) use (&$fcache,&$lang) {
        // parse the file if it's a new one. False indicates success, otherwise error message is returned
        if( !isset($fcache[$file])) {
            if( !file_exists("text/".$lang."/".$file.".html")) $lang = "en";
            if( !file_exists("text/".$lang."/".$file.".html")) return "<div class=\"alert\">ERROR: File ".$file." not found.</div>";
            $k = "";
            foreach(file("text/".$lang."/".$file.".html") as $l) {
                if( substr($l,0,1) == "|") $k = rtrim(substr($l,1));
                else $fcache[$file][$k] .= $l;
            }
        }
        return false;
    };
    $lang = $userdata && $userdata['language'] ? $userdata['language'] : "uk";
    list(,$file,$d) = $m;
    $params = explode(":",$d);
    $section = array_shift($params);
    if( $e = $parse($file)) return $e;
    if( !$fcache[$file][$section]) {
        $lang = "uk";
        if( $e = $parse($file)) return $e;
    }
    return preg_replace_callback("/%(\d+)/",function($i) use ($params) {
        return htmlspecialchars_decode($params[$i[1]-1]);
    },trim($fcache[$file][$section]));
},$data);

文本文件的格式为:

|key
replacement text
|otherkey
more text %1

无论如何,要指出:如果其中一个参数本身就是替换字符串怎么办?例如,如果我想要一个像“快来拜访他”的字符串怎么办? - 我希望它有类似的东西:

<t:person:visit:<t:grammar:pronoun_object_m>>

该文件将包含:

|visit
Come and visit %1 soon!

|pronoun_object_m
him

但是,当前函数会将参数作为文字<t:grammar:pronoun_object_m,并且会在短语末尾显示额外的>

  

快来访问&lt; t:grammar:pronoun_object_m吧!&gt;

实际上会显示为:

  

快来访问

由于未更新的替换看起来像HTML标记...

我很确定我需要一个递归的正则表达式,但是我对它们如何工作非常困惑。任何人都可以解释我如何“递归”我的正则表达式以允许这样的嵌入参数?

1 个答案:

答案 0 :(得分:2)

递归解决方案的问题是,它们与preg_replace的效果不佳。它们主要用于preg_match。原因是您只能访问在递归中重用的模式的最后(最内部)捕获。所以即使preg_replace_callback在这里也无济于事。

这是另一种可能性:

<t:person:visit:<t:grammar:pronoun_object_m>>中,您获得输出的原因是,您的正则表达式将与此匹配:

<t:person:visit:<t:grammar:pronoun_object_m>

(它不能更进一步,因为你在占位符中不允许>。)

有几种方法可以解决这个问题。对于初学者,您也可以在占位符中禁止<(而不仅仅是>):

"/<t:([^:]+):([^<>]+)>/"

现在,您的模式始终只能找到最里面的占位符。因此,您可以反复调用preg_replace_callback,直到不再进行替换。如何找到这个?添加可选的第四个和第五个参数:

do
{
    preg_replace_callback("/<t:([^:]+):([^<>]+)>/", $function, $data, -1, $count);
} while($count);

我还建议(为了易读性)在preg_replace_callback函数之外定义回调。