2017-06-30 89 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).'/'; 

等...

如果你遵循。