如何在具有非固定宽度的正则表达式中模拟lookbehind

问题描述 投票:2回答:2

我目前在特定情况下遇到了Regex的问题:我需要解析PHP源文件(特别是类)以查找在这些文件中定义的常量并将它们检索回输出。

这些常量可以有一些文档(这就是为什么我离开了Reflection的想法,因为通过Reflection检索常量只返回它们的名称和它们的值),这些可以在comments标记中提供。

我确实设法构建正则表达式的两个独立部分(1是注释标记,另一个是const声明)但我无法成功地将它们链接起来:似乎文件中的第一个常量也将包含所有先前声明的元素,直到它到达第一个注释块。

我的正则表达式如下(我不是一个正则表达的上帝,所以随意提出任何批评):

((\t\ )*(/\*+(.|\n)*\*/)\R+)?([\t| ]*(?|(public|protected|private)\s*)?const\s+([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*=\s*(.*);)

进行样本测试:Regex101

如果初始代码消失:

/**
*
*/
class Test {

   /**
    *
    */
    public const LOL = "damn";

   /**
    *
    */
    private const TEST = 5;

   public const plop = "dong";
}

我确实在那里寻找提示,我已经了解了正面的背后,但从我的理解,它只适用于固定宽度的模式。

我的想法已经不多了。

php regex comments constants
2个回答
1
投票

我倾向于采用多步骤方法:将每个类分开,然后寻找注释(最终)和常量。就正则表达而言,这可以通过实现

class\h*(?P<classname>\w+)[^{}]* # look for class literally and capture the name
(\{
    (?:[^{}]*|(?2))*             # the whole block matches the class content
\})

a demo on regex101.com


Now, to the comments and constants
^\h*
(?:(?P<comment>\Q/*\E(?s:.*?)\Q*/\E)(?s:.*?))?
(?:public|private)\h*const\h*
(?P<key>\w+)\h*=\h*(?P<value>[^;]+)

另见a demo for this step on regex101.com


The last step would be to clean the comments:
^\h*/?\*+\h*/?

查看cleansing on regex101.com的演示。


Lastly, you'll need two loops:
preg_match_all($regex_class, $source, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {
    preg_match_all($const_class, $match[0], $constants, PREG_SET_ORDER);
    foreach ($constants as $constant) {
        $comment = preg_replace($clean_comment, '', $constant["comment"]);

        # find the actual values here
        echo "Class: {$match["classname"]}, Constant Name: {$constant["key"]}, Constant Value: {$constant["value"]}, Comment: $comment\n";
    }
}

一个overall demo can be found on ideone.com。 注意演示和源代码中的各个正则表达式修饰符(尤其是verbosemultiline!)。


You can do it in an array as well:
$result = [];
preg_match_all($regex_class, $source, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {
    preg_match_all($const_class, $match[0], $constants, PREG_SET_ORDER);
    foreach ($constants as $constant) {
        $comment = trim(preg_replace($clean_comment, '', $constant["comment"]));
        $result[$match["classname"]][] = array('name' => $constant["key"], 'value' => $constant['value'], 'comment' => $comment);
    }
}

print_r($result);

1
投票

你可以在没有正面lookbehind的情况下做到这一点:你必须匹配一个注释,紧接着是一个const声明:

(?:(?:^/\*\*$\s+)((?:^ ?\*.*$\s*?)+)(?:\s+^\*/$\s+))?^\s+(public|protected|private) const (\S+)\s+= ([^;]+);

第一组将允许您检索文档:

  • 评论部分 (?:^/\*\*$\s+)找到了一个块评论的开头 ((?:^ ?\*.*$\s*?)+)代表包含您的评论内容的组 (?:\s+^\*/$\s+)评论结束
  • 声明部分: ^\s+跳过该行开头的空格 (public|protected|private) const一组确定能见度 (\S+)\s+= ([^;]+);团体的名称和价值
© www.soinside.com 2019 - 2024. All rights reserved.