我选择了如下所示的文本。我需要对其进行基本编辑,但无法理解我需要的正则表达式。也许只是漫长的一天,我没有看到我需要的东西。

示例数据:

START ITEM = 1235 
    BEGIN 
        WORD 
        RATE = 98 
        MORE WORDS 
        CODE = XX 
        STUFF 
    END 
    BEGIN 
        TEXT 
        MORE WORDS 
        RATE = 57 
        ADDITIONAL TEXT 
        CODE = YY 
        OTHER THINGS 
    END 
STOP 
START ITEM = 9983 
    BEGIN 
        WORD 
        RATE = 01 
        MORE WORDS 
        CODE = AA 
        STUFF 
    END 
    BEGIN 
        TEXT 
        MORE WORDS 
        RATE = 99 
        ADDITIONAL TEXT 
        CODE = XX 
        OTHER THINGS 
    END 
STOP 

我得到了一个 CODE 和一个 ITEM 编号,需要在适当的 BEGIN/END 中编辑费率 部分。幸运的是,这些部分使用 STOP/START BEGIN/END 进行了明确定义(它们是关键字,并且不在其他任何地方)。

我的工具箱是 Perl 正则表达式。*

我尝试的第一个解决方案没有用(值硬编码):

    $tx =~ s/(START \s ITEM \s = \s 9983.*? 
                            BEGIN 
                                .*? 
                               RATE \s = \s )\d+ 
                                    (.*?       # Goes too far 
                                CODE \s = \s XX) 
                        /$1$newRate$2 
                        /sx; 

因为指示的代码最终匹配太多,找到更远的正确代码但总是编辑第一个条目。

建议?


* 实际代码依赖于将正则表达式添加到正则表达式堆栈(一种后处理过滤器)中,每个正则表达式依次应用于文本以进行编辑。哎呀,如果我有文本,我可以做一个完整的解析器。但我希望不必打开该代码并坚持使用我已有的 API。

请您参考如下方法:

正则表达式不太适合解决此类问题。我推荐一个简单的迭代解决方案:

while (<FILE>) { 
    # push lines straight to output until we find the START that we want 
    print OUT $_; 
    next unless m/START ITEM = $number/; 
 
    # save the lines until we get to the CODE that we want 
    my @lines; 
    while (<FILE>) 
    { 
        push @lines, $_; 
        last if m/CODE = $code/; 
    } 
 
    # @lines now has everything from the START to the CODE. Get the last RATE in 
    # @lines and change its value. 
    my $strref = \( grep m/RATE/ @lines )[-1]; 
    $$strref = $new_value; 
 
    # print out the lines we saved and exit the loop 
    print OUT @lines; 
    last; 
} 

编辑:如果你真的想要一个正则表达式,你可以使用这样的东西(未经测试):

$tx =~ s/(START \s+ ITEM \s+ = \s+ 9983.*? 
                            BEGIN 
                                .*? 
                               RATE \s+ = \s+ )\d+ 
                                ( (?: (?! END ) . )* 
                                    CODE \s+ = \s+ XX) 
                        /$1$newRate$2 
                        /sx; 

添加的 (?: (?! END ) . )* 确保 RATE 和 CODE 之间的匹配不会跨越 END。但这将比非正则表达式方法慢得多。


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!