安全转义Raku正则表达式元字符

9

我想将一个像通配符的模式转换为 Raku 正则表达式。目前我是这样做的:

s :global {
    || $<question-mark> = '?'
    || $<asterisk>      = '*'
    || $<non-word>      = \W
} = $<question-mark> ?? '.' !! $<asterisk> ?? '.*' !! "\\$<non-word>";

用反斜杠前缀每个非单词字符是否正确?也就是说,这样做会错过任何应该转义的内容吗?或者会转义任何不应该转义的内容吗?

我有点困惑为什么Raku取消了Perl 5的quotemeta函数,这在这里将是理想的。虽然根据this question的答案,它不会经常需要,但在像这样的情况下,我只能手动编写一个我不确定是否足够的解决方案。


我相信反斜杠会被解释为转义字符,所以它应该是有效的。在引用方面,你可以不将值放在 \Q\E 之间吗? - Reilas
我相信反斜杠将被解释为转义字符,所以它应该是有效的。就引用而言,你能不能将值放在 \Q\E 之间? - Reilas
1
@Reilas Raku没有\Q和\E。 - Sean
1
@Reilas Raku没有\Q和\E。 - Sean
这里有什么有用的信息吗?https://dev59.com/7sTra4cB1Zd3GeqP9YA6 - jubilatious1
显示剩余2条评论
2个回答

11
Raku正则表达式可以包含带引号的字符串字面量:
say "food" ~~ /. "oo" /; # 「foo」

通过调用.raku,可以将一个Str转换为Raku源代码表示:

say "oh\n\"".raku; # "oh\n\""

这个处理了字符串构造的转义,使得它可以安全地输出到正则表达式中。

顺便说一下,虽然它仍处于实验阶段,即将推出的RakuAST将允许通过构建AST来构造正则表达式,这将提供另一种安全且更通用的解决方案。


2

使用我的 Rakudo 版本(v2022.07),以下转义包装工作:

  1. 将文字用 q[...] 包裹起来,
  2. 将上述的 q[…]<{...}> 包裹起来。

zshbash 命令行中测试为一行指令:

~$ zsh
~% raku -e 'say "food" ~~ / . <{ q[oo] }> /;'
「foo」

~% bash
~$ raku -e 'say "food" ~~ / . <{ q[oo] }> /;'
「foo」

可以尝试使用Raku的“Q语言”的不同变体:我在上面使用方括号取得了成功。请参阅:https://docs.raku.org/language/quoting.html。注意,确保添加< >尖括号,否则用{ }花括号包裹的文字将会看不见(它会被执行为代码块)。
~$ zsh
~% raku -e 'say "food" ~~ / { q[food] } /;'
「」
~% raku -e 'say "nothing" ~~ / { q[nothing] } /;'
「」

~% bash
~$ raku -e 'say "food" ~~ / { q[food] } /;'
「」
~$ raku -e 'say "nothing" ~~ / { q[nothing] } /;'
「」

以上可能对于跨平台的正则表达式最有用,而不是将 Linux/Unix 的“外部单引号和内部双引号”替换为 Windows 的“外部双引号和内部单引号”,反之亦然。您甚至可以尝试使用 qb[…] 来进行反斜杠转义识别(例如,对于有问题的 \n 换行符识别很有用):
~$ zsh
~% raku -e 'say "food\ntruck" ~~ / . <{qb[ ood \\n tru ]}> .. /;'
「food
truck」

~% bash
~$ raku -e 'say "food\ntruck" ~~ / . <{qb[ ood \\n tru ]}> .. /;'
「food
truck」

感谢@fecundf在理解/编码正则表达式匹配器中的插值方面给我们许多启发(请随意查看下面的帖子)。

https://www.nntp.perl.org/group/perl.perl6.users/2019/09/msg6960.html


我想要转义事先不知道的任意文本,这样看起来包含闭合括号的文本就不能被包裹在q[...]中,因为括号会提前关闭引用结构。如果我误解了,请提供一个处理任意文本的替代方案。 - Sean
@Sean,从广义上讲,单引号和双引号都是Raku中同一种Q语言的一部分。在之前的评论中,我指导你去了一个类似的问题,那里有一个答案这里。那个答案似乎不可接受,所以我发表了这个回答。事实上,如果你基本上是在你的代码中翻译?字符,你应该能够在后面的所有内容中使用q?…?。我可以在此基础上继续努力,并可能将其整合到上面。无论如何,我希望你会发现我的答案(和这个评论)有用。最好的问候。 - jubilatious1
我很欣赏你所付出的努力,但我觉得你误解了我的问题的要点。你开始提到了“取字面值”,但我并不想转义一个字面值;我想要将从文件中读取的任意字符串转换成正则表达式,其中?变为.*变为.*,并转义其他所有字符。Jonathan提供了一个解决方案,例如将字符串foo^*&amp;bar(不是作为字面值提供)转换为字符串"foo^".*"&amp;bar",这样就能达到目的。我无法看出如何利用你的回答来实现同样的目标。 - Sean
我很感激你所付出的努力,但是我觉得你误解了我的问题的要点。你一开始提到了“采取字面意思”,但是我并不想转义一个字面意思;我想要将从文件中读取的任意字符串转换成正则表达式,其中?会变成.*会变成.*,而其他字符则需要进行转义。Jonathan提供了一个解决方案,例如将字符串foo^*&bar(不作为字面意思提供)转换成字符串"foo^".*"&bar",这样就能达到目的。我无法看出如何将你的回答应用于同样的目标上。 - Sean
@Sean,看起来你接受了一个回答,这个回答与我一年前发布的回答完全一样。祝好。 - jubilatious1
显示剩余4条评论

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