用于捕获和修改 LFM 代码块的 Raku Regex
Raku Regex to capture and modify the LFM code blocks
更新:下面添加了更正的代码
我有一个 Leanpub 风格的 markdown* 文件,名为 sample.md
我想将其代码块转换为 Github 风格markdown 样式使用 Raku Regex
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]="```[=12=]"; # convert it into ```ruby
$key++;
while @in[$key].starts-with(" ") {
@out[$key]=@in[$key].trim-leading;
$key++;
}
@out[$key]="```";
}
}
@out[$key]=$val;
}
包含正则表达式的行给出
无法修改不可变对 (lang => True) 错误。
我刚开始使用正则表达式。我试过 (\w)
而不是 ([a-z]+)
,它给出了 Unrecognized backslash sequence: '\w'
错误,等等。
如何使用 Regex 正确捕获和修改 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, "```[=13=]";
$k++;
while @in[$k].starts-with(" ") {
push @out, @in[$k].trim-leading;
$k++; }
push @out, "```";
}
push @out, @in[$k];
$k++;
}
for @out {print "$_\n"}
TL;DR
TL? 然后阅读@jjemerelo 的优秀答案,它不仅提供了 one-line 解决方案,而且提供了更多以紧凑的形式 ;
DR? 哦,在我看来,你在这个答案中遗漏了一些被 JJ(合理地!)忽略的好东西。不过,JJ's 又一次成为了炸弹。先去读吧。 :)
使用 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
.
传递的索引的读写副本
但解决这个问题会导致另一个问题。而且代码是如此复杂,我得出结论,我最好不要再追究了。我已经解决了您眼前的障碍,希望对您有所帮助。
这一行似乎解决了问题:
say S:g /\{\: "lang" \= \" (\w+) \" \} /```[=10=]/ given "text.md".IO.slurp;
不过,让我们尝试解释一下发生了什么。该错误是一个正则表达式语法错误,是由于 :
后跟一个名称,并且所有内容都在卷曲内引起的。 {}
在正则表达式中运行代码。 Raiph 的答案(显然)是正确的,将其更改为 Perl 正则表达式。但我在这里所做的是将其更改为带有 :g
全局标志的 Raku 的 non-destructive substitution,以使其作用于整个文件(在行尾被吸;我已经将其保存到名为 text.md
的文件中)。所以这样做是为了吞噬你的目标文件,given
它被保存在 $_
主题变量中,并在替换完成后打印出来。好处是如果你想做更多的替换,你可以将另一个这样的表达式推到前面,它会作用于输出。
使用这种表达式在概念上总是比逐行处理文本更简单,而且可能更快。
更新:下面添加了更正的代码
我有一个 Leanpub 风格的 markdown* 文件,名为 sample.md
我想将其代码块转换为 Github 风格markdown 样式使用 Raku Regex
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]="```[=12=]"; # convert it into ```ruby
$key++;
while @in[$key].starts-with(" ") {
@out[$key]=@in[$key].trim-leading;
$key++;
}
@out[$key]="```";
}
}
@out[$key]=$val;
}
包含正则表达式的行给出 无法修改不可变对 (lang => True) 错误。
我刚开始使用正则表达式。我试过 (\w)
而不是 ([a-z]+)
,它给出了 Unrecognized backslash sequence: '\w'
错误,等等。
如何使用 Regex 正确捕获和修改 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, "```[=13=]";
$k++;
while @in[$k].starts-with(" ") {
push @out, @in[$k].trim-leading;
$k++; }
push @out, "```";
}
push @out, @in[$k];
$k++;
}
for @out {print "$_\n"}
TL;DR
TL? 然后阅读@jjemerelo 的优秀答案,它不仅提供了 one-line 解决方案,而且提供了更多以紧凑的形式 ;
DR? 哦,在我看来,你在这个答案中遗漏了一些被 JJ(合理地!)忽略的好东西。不过,JJ's 又一次成为了炸弹。先去读吧。 :)
使用 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
.
但解决这个问题会导致另一个问题。而且代码是如此复杂,我得出结论,我最好不要再追究了。我已经解决了您眼前的障碍,希望对您有所帮助。
这一行似乎解决了问题:
say S:g /\{\: "lang" \= \" (\w+) \" \} /```[=10=]/ given "text.md".IO.slurp;
不过,让我们尝试解释一下发生了什么。该错误是一个正则表达式语法错误,是由于 :
后跟一个名称,并且所有内容都在卷曲内引起的。 {}
在正则表达式中运行代码。 Raiph 的答案(显然)是正确的,将其更改为 Perl 正则表达式。但我在这里所做的是将其更改为带有 :g
全局标志的 Raku 的 non-destructive substitution,以使其作用于整个文件(在行尾被吸;我已经将其保存到名为 text.md
的文件中)。所以这样做是为了吞噬你的目标文件,given
它被保存在 $_
主题变量中,并在替换完成后打印出来。好处是如果你想做更多的替换,你可以将另一个这样的表达式推到前面,它会作用于输出。
使用这种表达式在概念上总是比逐行处理文本更简单,而且可能更快。