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

use*_*370 7 regex perl replace raku

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

kywrd a=b;c=d;
e=f;
fnctn z;
g=h;
Run Code Online (Sandbox Code Playgroud)

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

kywrd2 auto a=b;auto c=d;
auto e=f;
fnctn z;
g=h;
Run Code Online (Sandbox Code Playgroud)

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

kywrd a=b;c=d;
e=f;
fnctn z;
g=h;
Run Code Online (Sandbox Code Playgroud)

Hol*_*lli 5

One possible way that keeps the regexing to a minimum:

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;
Run Code Online (Sandbox Code Playgroud)

Personally I'd prefer the method form subst over the s// operator though.

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


rai*_*iph 5

单程:

# 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()";
Run Code Online (Sandbox Code Playgroud)

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

  • 我已经分解出一个命名的正则表达式来匹配一对。(有关为什么/如何调用正则表达式的详细信息,请参见我对Perl 6 / Raku中捕获和不捕获正则表达式范围差异的回答。)<pair>pair

  • 所述auto-ize子例程使用的匹配变量$/)作为其参数。这很方便,因为$0等会自动别名给与传递的匹配对象关联的编号捕获。

  • 我使用了该格式的语法,s [ ... ] = " ... "因为我认为这种用例更易读。(请参阅s///文档中有关“不同定界符”的提及。)

  • “ kywrd2 ...”字符串将被重复评估,并成为多个s:g匹配项中每个匹配项的一次替换。

  • $<pair>».&auto-ize.join()位是根据双引号字符串规则内插的代码。

  • $<pair>是的缩写$/<pair>,即的<pair>关键$/。它是指pairmatch变量关联的命名捕获。后者将s:g依次对应于多个匹配项中的每个匹配项。

  • +regex表达式中的量词<pair>+表示,如果匹配,它将产生一个List捕获(匹配)对象,而不是一个对象(就像表达式是just <pair>或的情况一样<pair>?)。

  • »将其LHS操作数视为树或列表(在这种情况下为一个或多个捕获/匹配对象的列表,每foo=bar;...对一个),并遍历其元素。对于每个“叶”元素,»都在其右侧执行操作。(它»是一个功能强大的运算符,但具有很好的简单用例,例如在这种情况下,它在概念上仅是方便且紧凑的for循环等效项。您可以编写它,>>就像使用ASCII一样。)

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

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

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;
Run Code Online (Sandbox Code Playgroud)

将其放入in.q并显示say结果out.q显示:

kywrd2 auto a=b;auto c=d;
auto e=f;
fnctn z;
g=h;
k=m;
fnctn y;
kywrd2 auto m=n;
auto k=j;
kywrd2 auto z=a;auto b=i;
kywrd2 auto c=x;auto e=i;
auto z=q;
fnctn o;
Run Code Online (Sandbox Code Playgroud)