2012-10-16 61 views
1

我正在做一個模板系統,藉此我可以輸入:遞歸正則表達式需要幫助

<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並會有一個額外>顯示出來的語句結束:

前來參觀<噸:語法:!很快pronoun_object_m>

這將實際顯示爲:

前來參觀

由於未解析更換,看上去就像一個HTML標籤...

我確信我需要一個遞歸正則表達式,但是我很困惑他們是如何工作的。任何人都可以請解釋我如何「遞歸」我的正則表達式,以允許這樣的嵌入式參數?

+0

你需要使用遞歸正則表達式模式。見http://stackoverflow.com/questions/1898905/recursive-regular-expression-to-process-nested-strings-enclosed-by-and和http://stackoverflow.com/questions/3241070/php-recursive-variable - 替換 –

+0

他已經說過了;)。另外,遞歸模式對於'preg_replace'實際上並不是很好。他們打算用於'preg_match'。 (請參閱我的回答,原因如下) –

回答

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功能之外回調。

+0

Duh ...編寫我自己的BBCode實現時,我已經做了類似的事情。我怎麼能忘記?感謝內存重啓,我會接受這個答案。 –