正则表达式查找块之间的模式
Regex find pattern between blocks
我正在 PHP 中构建一个模板引擎(类似 Django),它用相关数据替换 {{ }}
之间的所有内容。现在我能够做到这一点,但我面临的情况是只需要在块之间进行替换,例如 {% for y in x %}
循环块并忽略所有不在它们之间的括号。
我在 this regex101 example 中得到了一些结果,但只得到了每个块的第一个 {{ }}
。我想要做的是匹配每个块中的所有 {{ }}
,不包括外面的那些。
出于学习目的(非常好!)您有几种可能性:
多步骤方法(更容易理解和维护):
一个完整的正则表达式解决方案(更复杂,可能更"fancy")
广告 1)
用以下表达式匹配块(参见a demo on regex101.com):
{%\ for.*?%}
(?s:.+?)
{%\ endfor.*?%}
然后在每个块中寻找成对的{{...}}
:
{{\s*(.+?)\s*}}
在 PHP
中,这可能是:
<?php
$data = <<<DATA
{% for user in users %}
Hello, {{ user.name }}, you are {{ user.age }} {{ user.name }}
ssssssssssssssssssssss {{ user.name }}
sdsddddddddddddddddddddddddddddd
{% endfor %}
{% for dog in dogs %}
Your dog is {{ dog.age }} and likes {{ dog.food }}.
{% endfor %}
wwww
{{ user.name }}
DATA;
$block = '~
{%\ for.*?%}
(?s:.+?)
{%\ endfor.*?%}
~x';
$variable = '~{{\s*(.+?)\s*}}~';
if (preg_match_all($block, $data, $matches)) {
foreach ($matches as $match) {
if (preg_match_all($variable, $match[0], $variables, PREG_SET_ORDER)) {
print_r($variables);
}
}
}
?>
广告 2)
将所有有问题的变量与一个整体表达式匹配。在这里,您需要 \G
(匹配最后一场比赛的位置)和一些先行(参见 a demo for this one at regex101.com as well):
(?:{%\ for.+?%}
|
\G(?!\A)
)
(?s:(?!{%).)*?\K
{{\s*(?P<variable>.+?)\s*}}
现在让我们揭开这个表达式的神秘面纱:
(?:{%\ for.+?%}
|
\G(?!\A)
)
在这里,我们想要在最后一个位置匹配 {%\ for.+?%}
(我们需要 \
,因为我们处于详细模式) 或 与 \G
匹配。现在,事实是,\G
要么在最后一个匹配的位置匹配,要么在字符串的最开头匹配。我们不想要后者,因此否定。前瞻 (?!\A)
。
下一部分
(?s:(?!{%).)*?\K
有点像 "fast forward" 对有问题的有趣部分进行了处理。
分解,这个说
(?s: # open a non-capturing group, enabling the DOTALL mode
(?!{%). # neg. lookahead, do not overrun {% (the closing tag)
)*? # lazy quantifier for the non-capturing group
\K # make the engine "forget" everything to the left
现在,剩下的就简单了:
{{\s*(?P<variable>.+?)\s*}}
它基本上与广告 1) 的结构相同。
同样,在 PHP
中,这可能是:
<?php
$regex = '~
(?:{%\ for.+?%}
|
\G(?!\A)
)
(?s:(?!{%).)*?\K
{{\s*(?P<variable>.+?)\s*}}
~x';
if (preg_match_all($regex, $data, $variables)) {
print_r($variables[1]);
}
?>
综上所述,实际学习更复杂的模式通常是个好主意,但另一方面不要重新发明轮子——总有比你我更聪明的人可能已经考虑了一些边缘情况,等等。
我正在 PHP 中构建一个模板引擎(类似 Django),它用相关数据替换 {{ }}
之间的所有内容。现在我能够做到这一点,但我面临的情况是只需要在块之间进行替换,例如 {% for y in x %}
循环块并忽略所有不在它们之间的括号。
我在 this regex101 example 中得到了一些结果,但只得到了每个块的第一个 {{ }}
。我想要做的是匹配每个块中的所有 {{ }}
,不包括外面的那些。
出于学习目的(非常好!)您有几种可能性:
多步骤方法(更容易理解和维护):
一个完整的正则表达式解决方案(更复杂,可能更"fancy")
广告 1)
用以下表达式匹配块(参见a demo on regex101.com):
{%\ for.*?%}
(?s:.+?)
{%\ endfor.*?%}
然后在每个块中寻找成对的{{...}}
:
{{\s*(.+?)\s*}}
在 PHP
中,这可能是:
<?php
$data = <<<DATA
{% for user in users %}
Hello, {{ user.name }}, you are {{ user.age }} {{ user.name }}
ssssssssssssssssssssss {{ user.name }}
sdsddddddddddddddddddddddddddddd
{% endfor %}
{% for dog in dogs %}
Your dog is {{ dog.age }} and likes {{ dog.food }}.
{% endfor %}
wwww
{{ user.name }}
DATA;
$block = '~
{%\ for.*?%}
(?s:.+?)
{%\ endfor.*?%}
~x';
$variable = '~{{\s*(.+?)\s*}}~';
if (preg_match_all($block, $data, $matches)) {
foreach ($matches as $match) {
if (preg_match_all($variable, $match[0], $variables, PREG_SET_ORDER)) {
print_r($variables);
}
}
}
?>
广告 2)
将所有有问题的变量与一个整体表达式匹配。在这里,您需要 \G
(匹配最后一场比赛的位置)和一些先行(参见 a demo for this one at regex101.com as well):
(?:{%\ for.+?%}
|
\G(?!\A)
)
(?s:(?!{%).)*?\K
{{\s*(?P<variable>.+?)\s*}}
现在让我们揭开这个表达式的神秘面纱:
(?:{%\ for.+?%}
|
\G(?!\A)
)
在这里,我们想要在最后一个位置匹配 {%\ for.+?%}
(我们需要 \
,因为我们处于详细模式) 或 与 \G
匹配。现在,事实是,\G
要么在最后一个匹配的位置匹配,要么在字符串的最开头匹配。我们不想要后者,因此否定。前瞻 (?!\A)
。
下一部分
(?s:(?!{%).)*?\K
有点像 "fast forward" 对有问题的有趣部分进行了处理。
分解,这个说
(?s: # open a non-capturing group, enabling the DOTALL mode
(?!{%). # neg. lookahead, do not overrun {% (the closing tag)
)*? # lazy quantifier for the non-capturing group
\K # make the engine "forget" everything to the left
现在,剩下的就简单了:
{{\s*(?P<variable>.+?)\s*}}
它基本上与广告 1) 的结构相同。
同样,在 PHP
中,这可能是:
<?php
$regex = '~
(?:{%\ for.+?%}
|
\G(?!\A)
)
(?s:(?!{%).)*?\K
{{\s*(?P<variable>.+?)\s*}}
~x';
if (preg_match_all($regex, $data, $variables)) {
print_r($variables[1]);
}
?>
综上所述,实际学习更复杂的模式通常是个好主意,但另一方面不要重新发明轮子——总有比你我更聪明的人可能已经考虑了一些边缘情况,等等。