我的情况需要递归,我能够按照我需要的方式匹配大括号中的内容,但是我无法捕获周围的文本。
所以这就是示例文本:
这是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")}}
,但不能与周围的文本匹配,以达到我需要的结果。
我尝试了很多东西,但没有成功。
答案 0 :(得分:1)
您可以根据preg_split
和PREG_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 ).'/';
等等...
如果你跟随。