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

时间:2017-12-15 09:06:49

标签: php regex comments constants

我目前在特定情况下遇到了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";
}

我确实在那里寻找提示并且我已经了解了正面的背后隐藏,但据我所知,它只适用于固定宽度的模式。

我的想法已经不多了。

2 个答案:

答案 0 :(得分:1)

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

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

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

  • 评论部分
    • (?:^/\*\*$\s+)找到阻止评论的开头
    • ((?:^ ?\*.*$\s*?)+)代表包含评论内容的小组
    • (?:\s+^\*/$\s+)评论结束
  • 声明部分:
    • ^\s+跳过行尾的空白
    • (public|protected|private) const确定可见性的小组
    • (\S+)\s+= ([^;]+);组的名称和值

答案 1 :(得分: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

<小时/> 现在,对于注释和常量

^\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

<小时/> 最后一步是清理评论:

^\h*/?\*+\h*/?

查看cleansing on regex101.com的演示。

<小时/> 最后,您需要两个循环:

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!)。

<小时/> 您也可以在数组中执行此操作:

$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);