regex - 如何在 Perl 中进行条件贪婪匹配?

标签 regex perl conditional match greedy

我希望 Perl 解析代码文本并识别某些内容,示例代码:

use strict;
use warnings;

$/ = undef;

while (<DATA>) {
  s/(\w+)(\s*<=.*?;)/$1_yes$2/gs;
  print;
}

__DATA__
always @(posedge clk or negedge rst_n)
if(!rst_n)begin
        d1 <= 0; //perl_comment_4
        //perl_comment_5
        d2 <= 1  //perl_comment_6
                 + 2;
        end
else if( d3 <= d4 && ( d5 <= 3 ) ) begin
        d6 <= d7 +
                 (d8 <= d9 ? 1 : 0);
        //perl_comment_7
        d10 <= d11 <=
                      d12
                        + d13
                            <= d14 ? 1 : 0;
        end

匹配目标是满足以下所有条件的对象:

(1) 以组合word\s*<=开头.这里\s*可能有 0 个或多个空格、换行符、制表符。

(2) 前面提到的“组合”应该出自任何一对() .

(3)如果多个“组合”连续出现,则以第一个为开头。 (类似于左边界处的“贪婪”匹配)

(4) 它以第一个 ; 结束在(1)中提到的“组合”之后。

可能有word\s*<=;在代码注释中(注释中可能有任何内容);这让事情变得更加复杂。为了让生活更轻松,我已经对文本进行了预处理,扫描了评论并将其替换为 //perl_comment_6 之类的内容。 . (这个解决方案看起来相当麻烦和愚蠢。有没有更聪明、更优雅的解决方案?)

我想做什么:

对于所有匹配的 word\s*<= , 替换 wordword_yes .对于示例代码, d1 , d2 , d6 d10 应替换为 d1_是 , d2_yes , d6_yes d10_是 ,文本的所有其他部分应保持不变。

在我当前的代码中,我使用 s/(\w+)(\s*<=.*?;)/$1_yes$2/gs; , 正确识别 d1 , d2 d10 ,但无法识别 d6 并误认 d3 .

有什么建议?先谢谢了~

最佳答案

这比您想象的要复杂得多,如果不为您尝试处理的语言编写解析器,就不可能正确地完成。但是,如果您的样本始终是该语言的有限子集,那么您可能很幸运

我能看到的最好的方法是使用 split将括号中的字符串的所有子部分与要进行替换的“顶级”部分分开。然后可以对相关部分进行更改,并将拆分的部分重新连接在一起

即使这依赖于具有适当平衡括号的代码,并且出现在例如字符串或注释中的奇怪的左括号或右括号将抛出该过程。 split 中使用的正则表达式必须是递归的,以便嵌套括号可以匹配,并使其成为捕获正则表达式使 split返回字符串的所有部分,而不仅仅是匹配项之间的部分

此代码将按您的要求执行,但请注意,正如我所描述的,它非常脆弱

use strict;
use warnings;

my $data = do {
    local $/;
    <DATA>;
};

my @split = split / ( \( (?> [^()] | (?1) )* \) ) /x, $data;

for ( @split ) {
    next if /[()]/;
    s/ ^ \s* \w+ \K (?= \s* <= ) /_yes/xgm;
}

print join '', @split;


__DATA__
always @(posedge clk or negedge rst_n)
if(!rst_n)begin
        d1 <= 0; //perl_comment_4
        //perl_comment_5
        d2 <= 1  //perl_comment_6
                 + 2;
        end
else if( d3 <= d4 && ( d5 <= 3 ) ) begin
        d6 <= d7 +
                 (d8 <= d9 ? 1 : 0);
        //perl_comment_7
        d10 <= d11 <=
                      d12
                        + d13
                            <= d14 ? 1 : 0;
        end

输出

always @(posedge clk or negedge rst_n)
if(!rst_n)begin
        d1_yes <= 0; //perl_comment_4
        //perl_comment_5
        d2_yes <= 1  //perl_comment_6
                 + 2;
        end
else if( d3 <= d4 && ( d5 <= 3 ) ) begin
        d6_yes <= d7 +
                 (d8 <= d9 ? 1 : 0);
        //perl_comment_7
        d10_yes <= d11 <=
                      d12
                        + d13
                            <= d14 ? 1 : 0;
        end

关于regex - 如何在 Perl 中进行条件贪婪匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35552120/

相关文章:

linux - 使用 shell 遍历文件

regex - 在 R 中的特定字符串后检索数字

perl - 如何使用 Perl 将多个 Excel 工作表合并到一个工作簿中?

perl - 将散列传递给子例程而不更改其输入

swift - 对 Hashable 的条件一致性

c# - .NET 项目中的条件引用是否可以消除警告?

JavaScript 如果失败并显示 [""](包含空字符串的数组)

javascript - 在 MVC javascript 部分解析 @?

java - 匹配器无法匹配

MySQL REGEXP 选择数字