2017-06-30 45 views
1

我的情況需要遞歸,而且我能夠按照需要匹配大括號中的內容,但我無法捕獲周圍的文字。匹配不在大括號內的文本,同時也在捕獲括號後

因此,這將是示例文本:

這是FOO {{FOO}}和{{bar.function({{demo.funtion({{內}} == 「演示」) }}和{{條}}或 「富」)}} more_text {{富

我需要我的結果是這樣的:

0  =>  This is foo 
1  =>  {{foo}} 
2  =>  and 
3  =>  {{bar.function({{demo.funtion({{inner}} == "demo")}} and {{bar}} or "foo")}} 
4  =>  more_text {{foo 

有了這個:(\{\{([^{{}}]|(?R))*\}\})我已經能夠以匹配{{foo}}{{bar.function({{demo.funtion({{inner}} == "demo")}} and {{bar}} or "foo")}}非常好,但不是周圍的文字來達到我需要的效果。

我已經嘗試了很多東西,但沒有成功。

幫助將不勝感激。

+0

「捕捉周圍的文字」是什麼意思? – aaaaaa123456789

+0

請澄清要求。爲什麼要在輸出中清空元素?爲什麼最後一個'{{foo'從'more_text'中分離出來? –

+0

preg_match_all,而不是preg_match。 '/ \ {\ {| | [-0-9a-zA-Z ._] + | \} \} /'這是3種模式,然後您對它們進行處理並跟蹤開放式關閉括號匹配和正文匹配。然後你可以做嵌套。 – ArtisticPhoenix

回答

1

您可能使用基於preg_splitPREG_SPLIT_DELIM_CAPTURE標誌以下解決方案:

$re = '/({{(?:[^{}]++|(?R))*}})/'; 
$str = 'This is foo {{foo}} and {{bar.function({{demo.funtion({{inner}} == "demo")}} and {{bar}} or "foo")}} more_text {{foo'; 
$res = preg_split($re, $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); 
print_r($res); 
// => Array 
(
    [0] => This is foo 
    [1] => {{foo}} 
    [2] => and 
    [3] => {{bar.function({{demo.funtion({{inner}} == "demo")}} and {{bar}} or "foo")}} 
    [4] => more_text {{foo 
) 

PHP demo

整個模式與外部捕獲組一起捕獲,這就是爲什麼當添加PREG_SPLIT_DELIM_CAPTURE時,將此文本(即分割)添加到輸出數組中。

如果有不需要的空元素,PREG_SPLIT_NO_EMPTY標誌將丟棄它們。

更多細節

模式:我刪除從您的模式不必要的逃逸和符號,你不必逃避{}在PHP中的正則表達式時的背景是不夠的雷傑引擎演繹{這意味着您在所有情況下根本不需要轉義})。請注意,[{}][{{}}]相同,都會匹配單個字符,即{},無論您將多少個{}放入字符類中。我還通過將+貪婪量詞轉換爲所有格量詞0​​來提高其性能。

詳細說明:

  • ( - 第1點開始:1或更大 -
    • [^{}]++
      • {{ - - 2個連續{小號
      • (?:[^{}]++|(?R))* 0或多個序列除{和以外的符號(無回溯到這個模式是容許的)
      • | - 或
      • (?R) - 嘗試匹配整個圖案
  • }} - 一個}}
  • ) - 第1點結束。

PHP部分

當標記化而只使用一個令牌類型的字符串,很容易使用一個分裂的方法。由於PHP中的preg_split可以在保持文本匹配的情況下在正則表達式上分割,因此它非常適合這類任務。

唯一的問題是,如果匹配看起來是連續的或者在字符串的開始/結尾處,空條目可能會抓取到結果數組中。因此,PREG_SPLIT_NO_EMPTY很適合在這裏使用。

+0

你介意進一步解釋這個解決方案嗎?它的工作原理是100%,但我並沒有真正明白髮生了什麼事情。 – Aborted

+0

你是指PHP部分還是正則表達式部分?或兩者? –

+0

所以正則表達式部分和分裂是如何在這種情況下最好的解決方案。 – Aborted

1

我會用一個模式像這樣

$patt = '/(?P<open>\{\{)|(?P<body>[-0-9a-zA-Z._]+)|(?P<whitespace>\s+)|(?<opperators>and|or|==)|(?P<close>\}\})/' 

preg_match_all($patt, $text, $matches); 

產量遠遠要長,但你可以遍歷它,然後匹配的項目時,基本上它的tokeninzing的字符串。

它這樣

array (
0 => 
    array (
     0 => '{{', 
     1 => 'bar.function', 
     2 => '{{', 
     3 => 'demo.funtion', 
     4 => '{{', 
     5 => 'inner', 
     6 => '}}', 
     7 => ' ', 
     8 => '==', 
     9 => ' ', 
     10 => 'demo', 
     11 => '}}', 
     12 => ' ', 
     13 => 'and', 
     14 => ' ', 
     15 => '{{', 
     16 => 'bar', 
     17 => '}}', 
     18 => ' ', 
     19 => 'or', 
     20 => ' ', 
     21 => 'foo', 
     22 => '}}', 
    ), 
'open' => 
    array (
     0 => '{{', 
     1 => '', 
     2 => '{{', 
     3 => '', 
     4 => '{{', 
     5 => '', 
     6 => '', 
     7 => '', 
     8 => '', 
     9 => '', 
     10 => '', 
     11 => '', 
     12 => '', 
     13 => '', 
     14 => '', 
     15 => '{{', 
     16 => '', 
     17 => '', 
     18 => '', 
     19 => '', 
     20 => '', 
     21 => '', 
     22 => '', 
    ), 
), 
'body' => 
    array (
     0 => '', 
     1 => 'bar.function', 
     2 => '', 
     3 => 'demo.funtion', 
     4 => '', 
     5 => 'inner', 
     6 => '', 
     .... 
    ) 
) 

然後在一個循環中,你可以告訴匹配[0][0]open標籤,匹配[0][1]body比賽[0][3]是另一個open等,並通過跟蹤打開和關閉標籤,你可以工作出巢。它會告訴你什麼是一個開放的比賽身體的比賽勢均力敵的比賽,操作者匹配等等

你需要每一件事情,我沒有時間上的解決方案的完整的後處理...

快速示例將是一個open,然後是body,然後是close是一個變量。 open後跟body,另一個open是一個函數。 p 您也可以添加額外的圖案,像這樣插入(?P<function>function\.),其中的管道就像'/(?P<open>\{\{)|(?P<function>function\.)|...一樣。然後,你可以拿起關鍵字,如functionforeachblock等...你有什麼。

我用這種方法編寫了完整的模板系統。在我的模板系統我建至REGx在這樣

[ 'open' => '\{\{', 'function' => 'function\.', .... ] 

數組,然後將其壓縮到實際至REGx,讓生活變得簡單......

$r = []; 
    foreach($patt_array as $key=>$value){ 
    $r[] = '(?P<'.$key.'>'.$value.')'; 
    } 

    $patt = '/'.implode('|', $r).'/'; 

等...

如果你遵循。