【问题标题】:How do I match nested braces using regular expressions in PHP?如何在 PHP 中使用正则表达式匹配嵌套大括号?
【发布时间】:2011-01-21 12:56:54
【问题描述】:

我有一个想要匹配的 LaTeX 文档。我需要一个匹配以下内容的正则表达式:

\ # the backslash in the beginning
[a-zA-Z]+ #a word
(\{.+\})* # any amount of {something}

然而,她是关键;

在最后一行中,它 1. 需要贪心 2. 需要在其内部有一个匹配的{}

如果我有字符串\test{something\somthing{9}} 的含义 它会匹配整个。它需要按照这个顺序 ({})。使其与以下内容不匹配:

\LaTeX{} 是 \TeX{} 的文档准备系统

只是

\LaTeX{}

\TeX{}

帮助任何人?也许有人对匹配有更好的想法?我不应该使用正则表达式吗?

【问题讨论】:

  • 这不是你想要匹配的正则表达式,所以正则表达式不是最好的选择。话虽如此,您可以做到这一点,因为现在大多数正则表达式引擎都不正规,但这仍然不是一个好主意。
  • 如果我有任何其他选择,我会选择它。但我不知道我可以使用的任何其他东西。你有什么好主意吗?如果没有,看来我被卡住了宽度 RegEx。
  • 这不仅是偶数的 {}(你可以使用正则表达式),而且你还想确保 }}{{ 被拒绝(有相等数量的{}!),并且当 {} 出现在注释行中时,您会想要丢弃它们。简而言之:正则表达式不适合这个。
  • 尽管新的 Ruby 1.9 正则表达式引擎支持查找正确嵌套的括号,但我不确定这是否正是我推荐的做法。但如果你愿意,可以搜索\g,它可以让你选择一个命名的“子表达式”或类似的东西。
  • 那么什么适合这个呢?

标签: php regex


【解决方案1】:

这可以通过递归来完成:

$input = "\LaTeX{} is a document preparation system for the \TeX{}
\latex{something\somthing{9}}";

preg_match_all('~(?<token>
        \\\\ # the slash in the beginning
        [a-zA-Z]+ #a word
        (\{[^{}]*((?P>token)[^{}]*)?\}) # {something}
)~x', $input, $matches);

这正确匹配 \LaTeX{}\TeX{}\latex{something\somthing{9}}

【讨论】:

    【解决方案2】:

    可以使用 PHP,因为它支持递归正则表达式匹配。 但是,正如我所说,如果您在类似 LaTeX 的字符串中有 cmets,其中可以包含 {},这将失败。

    演示:

    $text = 'This is a \LaTeX{ foo { bar { ... } baz test {} done } } document
    preparation system for the \TeX{a{b{c}d}e{f}g{h}i}-y people out there';
    preg_match_all('/\\\\[A-Za-z]+(\{(?:[^{}]|(?1))*})/', $text, $matches, PREG_SET_ORDER);
    print_r($matches);
    

    产生:

    Array
    (
        [0] => Array
            (
                [0] => \LaTeX{ foo { bar { ... } baz test {} done } }
                [1] => { foo { bar { ... } baz test {} done } }
            )
    
        [1] => Array
            (
                [0] => \TeX{a{b{c}d}e{f}g{h}i}
                [1] => {a{b{c}d}e{f}g{h}i}
            )
    
    )
    

    快速解释:

    \\\\         # the literal '\'
    [A-Za-z]+    # one or more letters
    (            # start capture group 1   <-----------------+
      \{         #   the literal '{'                         |
      (?:        #   start non-capture group A               |
        [^{}]    #     any character other than '{' and '}'  |
        |        #     OR                                    |
        (?1)     #     recursively match capture group 1  ---+
      )          #   end non-capture group A
      *          #   non-capture group A zero or more times
      }          #   the literal '}'
    )            # end capture group 1 
    

    【讨论】:

      【解决方案3】:

      不幸的是,我认为这是不可能的。括号匹配(检测正确配对的嵌套括号)通常用作无法用有限状态机(例如正则表达式解析器)解决的问题的示例。您可以使用上下文无关的语法来做到这一点,但这不是正则表达式的工作方式。您最好的解决方案是使用像 {*[^{}]*}* 这样的正则表达式进行初始检查,然后使用另一个简短的脚本来检查它是否是偶数。

      总结:不要尝试只使用正则表达式。这不是单独使用正则表达式可以解决的问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-15
        • 1970-01-01
        相关资源
        最近更新 更多