php - 使用 Regex 匹配函数体

标签 php regex parsing text-parsing regex-lookarounds

给定一个虚拟函数:

public function handle()
{
  if (isset($input['data']) {
    switch($data) {
      ...
    }
  } else {
    switch($data) {
      ...
    }
  }
}

我的目的是获取该函数的内容,问题是匹配花括号 {...} 的嵌套模式。

我遇到了 recursive patterns但无法理解与函数主体匹配的正则表达式。

我已经尝试了以下(没有递归):

$pattern = "/function\shandle\([a-zA-Z0-9_\$\s,]+\)?". // match "function handle(...)"
            '[\n\s]?[\t\s]*'. // regardless of the indentation preceding the {
            '{([^{}]*)}/'; // find everything within braces.

preg_match($pattern, $contents, $match);

该模式根本不匹配。我确信这是错误的最后一位 '{([^{}]*)}/' 因为当主体内没有其他大括号时该模式有效。

将其替换为:

'{([^}]*)}/';

一直匹配到 if 语句中开关的关闭 } 并停在那里(包括开关的 } 但不包括if).

除了这个模式,同样的结果:

'{(\K[^}]*(?=)})/m';

最佳答案

更新#2

根据其他人的评论

^\s*[\w\s]+\(.*\)\s*\K({((?>"(?:[^"\\]*+|\\.)*"|'(?:[^'\\]*+|\\.)*'|//.*$|/\*[\s\S]*?\*/|#.*$|<<<\s*["']?(\w+)["']?[^;]+\3;$|[^{}<'"/#]++|[^{}]++|(?1))*)})

注意:一个简短的正则表达式,即 {((?>[^{}]++|(?R))*)}如果您知道您的输入不包含 { 就足够了或 }超出 PHP 语法。

这么长的正则表达式,它在什么邪恶情况下起作用?

  1. 你有[{}]在引号之间的字符串中 ["']
  2. 你让那些引号相互转义了
  3. 你有[{}]在评论区。 //.../*...*/#...
  4. 你有[{}]在 heredoc 或 nowdoc 中 <<<STR<<<['"]STR['"]

否则它意味着有一对开/关大括号,嵌套大括号的深度并不重要。

我们有失败的案例吗?

不,除非你的代码中有一个火星人。

 ^ \s* [\w\s]+ \( .* \) \s* \K               # how it matches a function definition
 (                             # (1 start)
      {                                      # opening brace
      (                             # (2 start)
           (?>                               # atomic grouping (for its non-capturing purpose only)
                "(?: [^"\\]*+ | \\ . )*"     # double quoted strings
             |  '(?: [^'\\]*+ | \\ . )*'     # single quoted strings
             |  // .* $                      # a comment block starting with //
             |  /\* [\s\S]*? \*/             # a multi line comment block /*...*/
             |  \# .* $                      # a single line comment block starting with #...
             |  <<< \s* ["']?                # heredocs and nowdocs
                ( \w+ )                      # (3) ^
                ["']? [^;]+ \3 ; $           # ^
             |  [^{}<'"/#]++                 # force engine to backtack if it encounters special characters [<'"/#] (possessive)
             |  [^{}]++                      # default matching bahaviour (possessive)
             |  (?1)                         # recurse 1st capturing group
           )*                                # zero to many times of atomic group
      )                             # (2 end)
      }                                      # closing brace
 )                             # (1 end)

格式化由@sln 的 RegexFormatter 完成软件。

我在现场演示中提供了什么?

Laravel 的 Eloquent Model.php文件(~3500 行)随机作为输入。看看这个: <强> Live demo

关于php - 使用 Regex 匹配函数体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38110833/

相关文章:

php - 如何使用php脚本创建mysql用户和数据库?

html - 使用 BeautifulSoup 消除嵌套 TD 中的 Span 元素

c++ - Boost::Spirit 在尝试解析带引号的字符串文字时无法编译

c# - 解析 CSV 格式的文本文件

php - 你用的哪个php变量调试功能? var_dump、print_r、var_export、其他?

php - 如何从输入在mysql中输入时间戳

php - 引用表1中的UID对表2实体进行计数

regex - 将一系列日期中的 Grep 作为文件名

php - 字符串到正则表达式的转换

regex - 如何使用python正则表达式匹配以哈希和问号开头的单词?