Raku正则表达式捕获和修改LFM代码块

9

更新: 下文已添加更正后的代码

我有一个名为 sample.mdLeanpub风格的Markdown文件,我想使用Raku Regex将其中的代码块转换为Github风格的Markdown格式

Here's a sample **ruby** code, which
prints the elements of an array:

{:lang="ruby"}
    ['Ian','Rich','Jon'].each {|x| puts x}

Here's a sample **shell** code, which
removes the ending commas and
finds all folders in the current path:

{:lang="shell"}
    sed s/,$//g
    find . -type d

为了捕获 {:lang="ruby"} 中的 lang 值,例如 ruby,并将其转换为:
```ruby

我使用这段代码

my @in="sample.md".IO.lines;
my @out;
for @in.kv -> $key,$val {
    if $val.starts-with("\{:lang") {
       if $val ~~ /^{:lang="([a-z]+)"}$/ { # capture lang
           @out[$key]="```$0"; # convert it into ```ruby
           $key++;
           while @in[$key].starts-with("    ") {
                 @out[$key]=@in[$key].trim-leading;
                 $key++;
           }
           @out[$key]="```";
       }
    }
    @out[$key]=$val;
}

正则表达式所在行出现了Cannot modify an immutable Pair (lang => True)的错误。

我刚开始使用正则表达式。我曾经尝试过(\w)而不是([a-z]+),但是它会产生一些错误,例如Unrecognized backslash sequence: '\w'

如何使用正则表达式正确捕获和修改lang值?

  • LFM格式仅为估计值。

修正后的代码:

my @in="sample.md".IO.lines;
my \len=@in.elems;
my @out;
my $k = 0;

while ($k < len) {
    if @in[$k] ~~ / ^ '{:lang="' (\w+) '"}' $ / { 
    push @out, "```$0";
    $k++;
    while @in[$k].starts-with("    ") {
        push @out, @in[$k].trim-leading;
        $k++;   }
    push @out, "```";
    }
    push @out, @in[$k];
    $k++;
}

for @out {print "$_\n"}

在你的for循环中,你可能想使用<->而不仅仅是-> - user0721090601
现在尝试了一下(使用操作符 <->),但是出现了 参数 '$key' 期望一个可写的容器(变量)作为参数,但是得到了一个没有容器的值 '0'(Int) 的错误。 - Lars Malmsteen
1
亲爱的@user0721090601... 您能否说明为什么<->胜过->,并可能提供相应的文档页面参考(我找不到)? - librasteve
1
@p6steve 这里有文档链接(https://docs.raku.org/type/Block#index-entry-%3C-%3E)。(我是通过在文档搜索框中输入<->找到它的;也许它是针对你的评论添加到搜索索引中的?) - raiph
2个回答

10

简述:

  • TL是啥? 阅读@jjemerelo的卓越回答,它不仅提供了一个单行解决方案,还以紧凑的形式给出了更多内容;

  • DR是什么?唉,依我之见,您在这篇答案中错过了一些好东西,而JJ(合理地!)忽略了这些内容。虽然JJ的确很棒。建议优先阅读他的回答。(译者注: TL和DR分别是Too long, don't read 和Didn’t Read 的缩写,常用于概述情况或文章摘要的开头,目的是告诉读者简短概要)

使用Perl正则表达式

有许多种语言实现了正则表达式。你所使用的正则表达式模式是Perl正则表达式,但你没有告诉Raku。因此,它会将你的正则表达式解释为Raku正则表达式而不是Perl正则表达式。这就像是将Python代码输入perl解释器中一样。所以,报错信息毫无用处。


一个选择是切换到Perl正则表达式处理。要做到这一

      /^{:lang="([a-z]+)"}$/

需要在开头使用m:P5

m :P5 /^{:lang="([a-z]+)"}$/

当你在使用/.../时,如果它假定你要立即匹配,那么m就是隐式的。但因为:P5“副词”被添加来修改Raku解释正则表达式的方式,所以也必须加上m

:P5仅支持有限的Perl正则表达式模式。话虽如此,在你所提出问题的正则表达式中应该已经足够了。

使用Raku正则表达式

如果你想使用Raku正则表达式,你需要学习Raku正则表达式语言。

Raku正则表达式语言的“精神”与Perl的相同,并且一些基本语法与Perl的相同,但不同之处足以让你将其视为另一种正则表达式方言,只是相对于Perl的正则表达式,它通常更加强大。

要将正则表达式改写为Raku格式,我认为应该是:

/ ^ '{:lang="' (<[a..z]>+) '"}' $ /

(利用 Raku 正则表达式中空格被忽略的特性。)

你代码中的其他问题

修复了正则表达式后,你的代码还有其他问题。

我遇到的第一个问题是 $key 是只读的,所以 $key++ 会失败。一种解决方法是使它可写,通过编写 -> $key is copy ...,使 $key 成为传递给 .kv 的索引的可读写副本。

但是,修复这个问题会导致另一个问题。而且代码非常复杂,我认为最好不要深入追究。我解决了你目前的障碍,希望能有所帮助。


谢谢你的回答。我不知道Perl 5和Raku Regex之间有区别。实际上,我昨天下午才开始学习Raku Regex,而且已经有一段时间没有使用Raku了,所以我忘记了一些细节。 - Lars Malmsteen
是的,$key 是只读的,会导致错误,但由于正则表达式的错误,我无法调试它。将其改为 $key is copy, $val 可以解决问题。顺便说一句,使用 (\w+) 捕获更好。实际上,我最初就使用了 (\w+),但可能是因为 Perl 5 正则表达式的原因,它会出错;现在它可以正常工作了。现在只剩下一件事了。需要在代码块的末尾添加包含的 \```。 - Lars Malmsteen
1
@LarsMalmsteen 有道理。 :) 我不知道你何时接受了我的答案,但如果你在看到JJs之前就接受了我的答案,并且/或者想让后来的读者先看到它(我这样认为!),请知道在SO上改变你的想法是可以的(甚至多次),如果你后来决定一个不同的答案,最新的编辑是现在最好的答案。我认为我的答案很好,但始终要考虑未来的读者,并且希望他们首先关注JJs简短、精炼和我认为更好的回答“如何使用正则表达式正确捕获和修改lang值”。 - raiph
@LarsMalmsteen “顺便说一下,使用捕获组(\w+)效果更好。” 我现在才意识到我在Raku正则表达式中犯了一个错误。我写的是([a..z]+),它将匹配一个或多个模式为a..z的序列,即以a开头并以z结尾的四个字母子字符串。这根本不是我想要的!我已经编辑了我的答案,将Raku等效于Perl正则表达式的[a-z]<[a..z]>。有关Raku正则表达式中字符范围的进一步讨论,请参见文档 - raiph

9

这个一行代码似乎可以解决问题:

say S:g /\{\: "lang" \= \" (\w+) \" \} /```$0/ given "text.md".IO.slurp;

让我们尝试解释一下发生了什么。这个错误是一个正则表达式语法错误,因为在花括号内有一个冒号后跟着一个名称::{} 运行正则表达式内的代码。Raiph的回答(显然)是正确的,通过将其更改为Perl正则表达式。但我所做的是将其更改为Raku的非破坏性替换,并使用全局标志:g来使其作用于整个文件(在该行的末尾读取整个文件;我将其保存到名为text.md的文件中)。所以这样做的效果是读取目标文件,并将其保存在$_主题变量中,一旦替换完成,就打印出来。好处是如果你想进行更多的替换,你可以把另一个这样的表达式放在前面,它会作用于输出结果。使用这种类型的表达式始终比逐行处理文本概念上更简单,可能也更快。

1
谢谢你的回答。这是一个有帮助的答案,因为我刚刚尝试了它并且它有效。我从昨天下午开始学习Raku的正则表达式部分。关于那个一行代码如何工作的解释很好。 - Lars Malmsteen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接