2012-10-12 47 views
4

我長相的工作就像該字符串:遞歸正則表達式不起作用

abc {def ghi {jkl mno} pqr stv} xy z 

,我需要把數字括號包含在標籤的東西,所以它應該是這樣的

abc <tag>def ghi <tag>jkl mno</tag> pqr stv</tag> xy z 

我試過

'#(?<!\pL)\{ (([^{}]+) | (?R))* \}(?!\pL)#xu' 

,但我所得到的只是<tag>xy z</tag>。請幫助,我做錯了什麼?

回答

3

如何兩個步驟:

s!{!<tag>!g;
s!}!</tag>!g;

(perl的格式轉換成您的格式如適用)

也許這樣的:

1 while s!{([^{}]*)}!<tag>$1</tag>!g;

+0

已經想過了。這很簡單,但如果找不到匹配的括號,可能會導致打破標記。 – tijagi

+0

您可以重複調用搜索/替換。 (答案已更新) –

5

嵌套結構是根據定義對於正則表達式來說太複雜了(是的,PCRE支持遞歸,但這對替換問題沒有幫助)。有兩種可能的選擇(無論如何使用正則表達式)。首先,您可以簡單地通過打開標籤來替換開頭的括號,而對於結束標籤來說也是如此。然而,這將轉化無與倫比的括號,以及:

$str = preg_replace('/\{/', '<tag>', $str); 
$str = preg_replace('/\}/', '</tag>', $str); 

另一種選擇是隻替換匹配{},但你必須要反覆做,因爲一個呼叫preg_replace不能代替多個嵌套層次:

do 
{ 
    $str = preg_replace('/\{([^{]*?)\}/', '<tag>$1</tag>', $str, -1, $count); 
} 
while ($count > 0) 

編輯:雖然PCRE支持遞歸與(?R)這很可能不會有替代的幫助。原因在於,如果捕獲組被重複,則其引用將僅包含最後一次捕獲(即,當在aaaab中匹配/(a|b)+/時,$1將包含b)。我想這和遞歸是一樣的。這就是爲什麼你只能替換最內層的匹配,因爲它是遞歸中捕獲組的最後一個匹配。同樣,你不能嘗試用遞歸捕獲{}並替換它們,因爲它們可能會被匹配任意次數,並且只有最後一次匹配會被替換。

只匹配正確的嵌套語法,然後替換最裏面或最外面的匹配括號也不會幫助(有一個preg_replace調用),因爲多個匹配不會重疊(所以如果找到3個嵌套括號,則內部2個括號他們自己將被忽略進一步的比賽)。

+0

這就是'(?R)'所代表的意思。 – tijagi

+0

該定義僅適用於數學意義上表達式爲「正則表達式」的情況。例如,PHP使用的PCRE在任何想象中都是不規則的:例如,你可以(像提問者那樣)使用'(?R)'來表達*遞歸*。現在,這是否是一個好主意是另一個問題,但它不應該是不可能的。 –

+1

你是對的,PCRE支持'(?R)',但我似乎無法找到任何(推薦)使用它作爲'preg_replace'的例子。它通常似乎只用於'preg_match'。 –