匹配不在花括号内的文本,同时也捕获括号后面的文本

时间:2017-06-30 08:55:16

标签: php regex

我的情况需要递归,我能够按照我需要的方式匹配大括号中的内容,但是我无法捕获周围的文本。

所以这就是示例文本:

  

这是foo {{foo}}和{{bar.function({{demo.funtion({{inner}} ==“demo”)}}和{{bar}}或“foo”)}} more_text {{foo

我需要我的结果看起来像这样:

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")}},但不能与周围的文本匹配,以达到我需要的结果。

我尝试了很多东西,但没有成功。

2 个答案:

答案 0 :(得分: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标志将丢弃它们。

更多详情

模式:我从模式中删除了不必要的转义符和符号,因为当上下文足够regex时,您不必在PHP正则表达式中转义{}引擎推导{意味着你根本不需要在所有上下文中转义}。请注意[{}][{{}}]相同,无论有多少{和{},都会匹配{}的单个字符。 {1}}你输入了角色类。我还通过将+贪婪量词变为占有量词++来增强其表现。

详细说明:

  • ( - 第1组开始:
    • {{ - 连续2次{ s
    • (?:[^{}]++|(?R))* - 0个或更多序列:
      • [^{}]++ - 除{}以外的1个或多个符号(不允许回溯到此模式)
      • | - 或
      • (?R) - 尝试匹配整个模式
  • }} - }}子字符串
  • ) - 第1组结束。

PHP部分

使用一种令牌类型对字符串进行标记时,很容易使用拆分方法。由于PHP中的preg_split可以在保留匹配文本的同时在正则表达式上进行拆分,因此非常适合此类任务。

唯一的麻烦是,如果匹配似乎是连续的,或者在字符串的开头/结尾处,空条目可能会爬进结果数组。因此,PREG_SPLIT_NO_EMPTY在这里很好用。

答案 1 :(得分:1)

我会使用这样的模式

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

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

输出很远但你可以循环它然后匹配项目,基本上它是字符串的标记。

就像这样

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\.)|...。然后你可以选择function foreach block之类的关键字......你有什么。

我用这种方法编写了完整的模板系统。在我的模板系统中,我在这样的数组中构建了RegX

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

然后将其压缩到实际的regx,让生活变得轻松......

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

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

等等...

如果你跟随。