我正在学习正则表达式,并希望用PHP编写模板引擎。
考虑以下“模板”:
<!DOCTYPE html>
<html lang="{{print("{hey}")}}" dir="{{$dir}}">
<head>
<meta charset="{{$charset}}">
</head>
<body>
{{$body}}
{{}}
</body>
</html>
我设法创建了一个除{{}}之外的任何内容的正则表达式。
这是我的正则表达式:
{{[^}]+([^{])*}}
只有一个问题。如何在{
代码中使用文字}
和{{}}
?
找不到{{print("{hey}")}}
。
提前致谢。
答案 0 :(得分:2)
你可以使用“。”而不是字符类。但是你必须使用非贪婪的量词:
\{\{(.+?)\}\}
量词“+?”意味着它将消耗最少必要数量的字符。
考虑这个例子:
<table>
<tr>
<td>{{print("{first name}")}}</td><td>{{print("{last name}")}}</td>
</tr>
</table>
使用贪婪的量词(+或*),你只得到一个结果,因为它看到第一个{{
,然后.+
消耗尽可能多的字符,只要它模式匹配:
{{print("{first name}")}}</td><td>{{print("{last name}")}}
使用非贪婪的(+?或*?),你会得到两个不同的结果:
{{print("{first name}")}}
{{print("{last name}")}}
答案 1 :(得分:2)
这是一个匹配双花括号内的内容的模式:
$pattern = <<<'LOD'
~
(?(DEFINE)
(?<quoted>
' (?: [^'\\]+ | (?:\\.)+ )++ ' |
" (?: [^"\\]+ | (?:\\.)+ )++ "
)
(?<nested>
{ (?: [^"'{}]+ | \g<quoted> | \g<nested> )*+ }
)
)
{{
(?<content>
(?:
[^"'{}]+
| \g<quoted>
| \g<nested>
)*+
)
}}
~xs
LOD;
紧凑版:
$pattern = '~{{((?>[^"\'{}]+|((["\'])(?:[^"\'\\\]+|(?:\\.)+|(?:(?!\3)["\'])+)++\3)|({(?:[^"\'{}]+|\g<2>|(?4))*+}))*+)}}~s';
内容位于第一个捕获组中,但您可以使用带有详细版本的命名捕获'content'
。
如果此模式较长,它允许在引用部分内包含转义引号的所有内容,并且在很多情况下比简单的惰性量词更快。
也允许使用嵌套的花括号,您可以毫无问题地编写{{ doThat(){ doThis(){ }}}}
。
引号的子模式也可以这样写,避免为单引号和双引号重复同样的事情(我在紧凑版本中使用它)
(["']) # the quote type is captured (single or double)
(?: # open a group (for the various alternatives)
[^"'\\]+ # all characters that are not a quote or a backslash
| # OR
(?:\\.)+ # escaped characters (with the \s modifier)
| #
(?!\g{-1})["'] # a quote that is not the captured quote
)++ # repeat one or more times
\g{-1} # the captured quote (-1 refers to the last capturing group)
注意:必须在nowdoc语法中使用反斜杠\\
,但在单引号内使用\\\
或\\\\
。
详细模式的解释:
该模式分为两部分:
定义部分有助于避免在主模式中多次重复相同的子模式或使其更清晰。您可以定义稍后将在此空间中使用的子模式:
(?(DEFINE)....)
此部分包含2个已命名的子模式:
嵌套
的详细信息(?<nested> # open the named group "nested"
{ # literal {
## what can contain curly brackets? ##
(?> # open an atomic* group
[^"'{}]+ # all characters one or more times, except "'{}
| # OR
\g<quoted> # quoted content, to avoid curly brackets inside quoted parts
# (I call the subpattern I have defined before, instead of rewrite all)
| \g<nested> # OR curly parts. This is a recursion
)*+ # repeat the atomic group zero or more times (possessive *)
} # literal }
) # close the named group
(*有关atomic groups和possessive quantifiers的更多信息)
但所有这些只是定义,模式始于:{{
然后我打开一个命名的捕获组(content
),然后我描述了里面可以找到的东西,(这里没什么新东西)。
我使用修饰符x
和s
。 x
激活详细模式,允许在模式中自由放置空格(对缩进很有用)。 s
是单线模式。在此模式下,点可以匹配换行符(默认情况下不能)。我使用此模式是因为子模式quoted
中有一个点。
答案 2 :(得分:0)
使用{{(.*?)}}
让你的正则表达不那么贪心。
答案 3 :(得分:0)
我明白了。不要问我怎么做。
{{[^{}]*("[^"]*"\))?(}})
这几乎可以匹配任何东西......例如:
{{print("{{}}}{{{}}}}{}}{}{hey}}{}}}{}7")}}