0

我正在学习正则表达式,并想用 PHP 编写一个模板引擎。

考虑以下“模板”:

<!DOCTYPE html>
<html lang="{{print("{hey}")}}" dir="{{$dir}}">
<head>
    <meta charset="{{$charset}}">
</head>
<body>
    {{$body}}
    {{}}
</body>
</html>

我设法创建了一个正则表达式,它可以找到除 {{}} 之外的任何内容。

这是我的正则表达式:

{{[^}]+([^{])*}}

只有一个问题。如何允许文字{}{{}}标签中使用?

它不会找到{{print("{hey}")}}

提前致谢。

4

4 回答 4

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}")}}
于 2013-08-02T23:40:01.120 回答
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

(* 有关原子团所有格量词的更多信息)

但所有这些都只是定义,模式真正开始于:然后我{{ 打开一个命名的捕获组(content

我使用 to 修饰符xs. x激活详细模式,允许在模式中自由放置空格(用于缩进)。s是单行模式。在这种模式下,点可以匹配换行符(默认情况下不能)。我使用这种模式是因为 subpattern 中有一个点quoted

于 2013-08-03T00:52:08.307 回答
0

使用{{(.*?)}}.

于 2013-08-02T23:39:09.067 回答
0

我想到了。不要问我怎么做。

{{[^{}]*("[^"]*"\))?(}})

这几乎可以匹配任何东西..例如:

{{print("{{}}}{{{}}}}{}}{}{hey}}{}}}{}7")}}
于 2013-08-03T00:00:48.747 回答