使用正则表达式替换条件子表达式

时间:2019-10-30 09:29:35

标签: regex perl replace raku

我的文本输入与以下所示类似。我想在每个'a = b'模式前添加单词auto,但前提是它是关键字kywrd之后的序列的一部分(由分号分隔)。

kywrd a=b;c=d;
e=f;
fnctn z;
g=h;

所以我在这里寻找的输出是:

kywrd2 auto a=b;auto c=d;
auto e=f;
fnctn z;
g=h;

以下Perl6(Raku?)代码使用正则表达式添加auto关键字,但仅在 first a=b模式之前。有没有一种简单的方法可以执行序列中所有模式的替换;保留g=h;不变?

my Str $x = slurp "in.q";
$x ~~ s:g /kywrd\s+(\w+)\=(\w+)\;/kywrd2 auto $0=$1\;/;
spurt "out.q", $x;

3 个答案:

答案 0 :(得分:5)

一种使正则表达式最小化的可能方法:

sub repl ($input) 
{ 
    $input.Str
    .split(';', :skip-empty)
    .map( 'auto ' ~ * ~ ';')
    .join('')
 };

 my $foo = 'kywrd a=b;c=d;d=e;'; 
 $foo ~~ s:g /kywrd \s+ (.+)/kywrds2 { repl($0) }/; 
 $foo.say;

相对于subst运算符,我个人更喜欢使用s//形式的方法。

$foo .= subst(/ kywrd \s+ (.+) /, "kywrds2 { repl($0) }", :g); 

答案 1 :(得分:5)

一种方法:

const common = require("./common");

module.exports = {
    test: function(){
       console.log(common.data);
    }
}

对于稍微熟悉Raku的人来说,我展示的所有代码都将很容易理解,但是我还是会解释它。

  • 我已经分解出一个命名的正则表达式来匹配一对。 (有关# Create a separate named regex that captures an `x=y;` pair: my regex pair { (\w+) \= (\w+) \; (\s*) } # (Capture `(\s*)` so formatting between pairs is retained) # Generate and return 'auto'-ized replacement of a captured pair: sub auto-ize ($/) { "auto $0=$1;$2" } $x ~~ s:g { kywrd \s+ <pair>+ } = "kywrd2 $<pair>».&auto-ize.join()"; 为何/如何调用<pair>正则表达式的详细信息,请参见my answer to Difference in capturing and non-capturing regex scope in Perl 6 / Raku。)

  • pair子例程使用the match variableauto-ize)作为参数。这很方便,因为$/等会自动别名为与传递的匹配对象关联的编号捕获。

  • 我使用了$0形式的语法,因为我认为这种用例更易读。 (请参见s/// doc中提到的“不同定界符”。)

  • “ kywrd2 ...”字符串将被反复求值并替换为一个匹配项,对于多个s [ ... ] = " ... "匹配项中的每个匹配项都为一次。

  • s:g位是双引号字符串规则下的代码interpolated

  • $<pair>».&auto-ize.join()表示$<pair>的缩写,即$/<pair>的{​​{1}}键。它是指与the match variable关联的<pair>命名捕获。后者将依次对应于多个$/匹配中的每个匹配。

  • 正则表达式pair中的s:g量词表示,如果匹配,它将生成捕获(匹配)对象的 + 而不是仅仅一个(如果表达式只是<pair>+List就是这种情况)。

  • »将其LHS操作数视为树或列表(在这种情况下,是一个<pair>对中一个或多个捕获/匹配对象的列表),并遍历其元素。对于每个“叶”元素,<pair>?在其右侧进行操作。 (foo=bar;...是一个功能强大的运算符,但具有很好的简单用例,例如在这种情况下,它在符号上非常方便且紧凑,等效于»循环。如果您将其写为»,首选ASCII。)

  • for调用>>子例程,就好像它是一个方法一样,使用其左侧的操作数作为第一个参数。

来自@PolarBear答案的测试输入数据:

.&auto-ize

将其放入auto-ize中,然后kywrd a=b;c=d; e=f; fnctn z; g=h; k=m; fnctn y; kywrd m=n; k=j; kywrd z=a;b=i; kywrd c=x;e=i; z=q; fnctn o; 将生成的in.q显示为:

say

答案 2 :(得分:3)

不是很优雅,但是可行的代码(古老的方式)

#!/usr/bin/perl

use strict;
use warnings;

OUTER: while(<DATA>) {
    if( s/kywrd /kywrd2 / ) {
        do {
            if( ! s/(\w+)=(\w+)/auto $1=$2/g ) {
                print;
                next OUTER;
            }
            print;
        } while ( <DATA> );
    } else {
        print;
    }
}

__DATA__
kywrd a=b;c=d;
e=f;
fnctn z;
g=h;
k=m;
fnctn y;
kywrd m=n;
k=j;
kywrd z=a;b=i;
kywrd c=x;e=i;
z=q;
fnctn o;

我需要看看Raku-它是哪种动物。