在每个非字母数字字符前放置一个转义符

Place an escape sign before every non-alphanumeric characters

我试图在每个非字母数字字符前放置一个转义符号:

 > my $b = "!@#%^||" ~ "/welcome xyz:!@#$%^&*()|:;.,?/-."
!@#%^||/welcome xyz:!@#$%^&*()|:;.,?/-.

> my $c = $b.subst(/<:!L + :!N - [./-]>/, "\" ~ $/, :g)
\ \ \ \ \ \ \ /welcome\ xyz\ \ \ \ \ \ \ \ \ \ \ \ \ \ .\ \ /-.

这是第一次运行编译代码后的结果。在我第二次 运行 代码之后,结果是一长串重复匹配。如果我使用“?”,结果类似量词。

> my $c = $b.subst(/<:!L + :!N - [./-]>/, "\" ~ $/, :g)
\! @ # % ^ | |   : ! @ # $ % ^ & * ( ) | : ; , ?\! @ # % ^ | |   : ! @ # $ % ^ & * ( ) | : ; , ?\! @ # % ^ | |      # This is truncated long string of undesired result.

然后我尝试用 comb 替换单个字符,但出现多个错误

> $b.comb.map( {.subst(/<:!L + :!N - [./-]>/, "\" ~ $/)} )
Use of uninitialized value element of type Any in string context.
Methods .^name, .raku, .gist, or .say can be used to stringify it to something meaningful.
  in block  at <unknown file> line 1
(\! \! \@ \# \% \^ \| / w e l c o m e \ x y z \ \: \! \@ \# $ \% \^ \& \* \( \) \| \: . \ \, / - .)

如果我再次 运行 代码,结果会略有不同:

(\ \! \@ \# \% \^ \| / w e l c o m e \ x y z \ \: \! \@ \# $ \% \^ \& \* \( \) \| \: . \ \, / - .)

我也无法加入此列表:

> $b.comb.map( { if $_.so { .subst(/<:!L + :!N - [./-]>/, "\" ~ $/)} } ).join
Use of uninitialized value element of type Any in string context.
Methods .^name, .raku, .gist, or .say can be used to stringify it to something meaningful.
  in block  at <unknown file> line 1
  in block <unit> at <unknown file> line 1

例程 tr/// 没有完成我试图完成的工作。

在字符串中的每个非数字字符前放置“\”的快速方法是什么?看似简单,却又如此困难。谢谢。

TL;DR 将替换包装在代码块中 ({ ... })。

$/subst

一起使用时出现问题

引用 $/ doc:

set to the result of the last Regex match

这并不总是正确的。

引用,适当添加强调,来自Rakudo[=110]对匹配变量的“发布” =] 我写的 部分(在对您写的另一个 SO Q 的回复中):

the regex/grammar engine makes a conservative call about [when it's worth "publishing" (updating) $/]. By "conservative" I mean that the engine often avoids doing publication, because it slows things down and is usually unnecessary. Unfortunately it's sometimes too optimistic about when publication is actually necessary. Hence the need for programmers to sometimes intervene by explicitly inserting a code block to force publication of match variables...

上述措辞的上下文是您之前的 Q,不是 subst 的替代。而且我还没有阅读编译器代码来检查这个新 Q 的场景中发生了什么。

但是,当我阅读您的新 SO Q 时,我立即感到相当有信心,当考虑到文档关于 $/ 的措辞“设置为最后一个 Regex 匹配的结果”时,并在subst 调用的上下文,如果传递给 subst 的替换只是一个字符串.


要更详细地了解当您 将替换包装在代码块中时发生的情况,可以将 $/ 与代码块一起使用包装它但仍然say它“en passant”:

my $c = $b.subst(/<:!L + :!N - [./-]>/, "\" ~ $/.&{ say $_; $_ }, :g);

如您所见,如果您 运行 该代码,$/ 最初设置为 Nil

然后,after 那个语句已经执行,但是 before next 语句是执行后,$/ 值会更新。这就是为什么您在每个后续语句中得到 不同(但仍然无用!)的原因。也就是说,$/正在更新,但是更新来不及如果你只使用$/ 在用于替换的字符串表达式中,而不是将其放在代码块中。

在最近的一个Rakudo

中使用subst时的解决方法

再次引用同一文档:

A fresh [$/] is created in every routine.

同样,我没有检查编译器源代码,但我有信心在每个 Routine but in every Block

中都会创建一个新的 $/

所以我测试了将替换包装在代码块中,果然这意味着匹配变量“publication”($/ 等的更新)did 发生了.

所以我认为这是一个解决方案。

另一个解决方案

What is a quick way to place "\" before every non-alnum char in a string?

$_ = '42!@#%^||' ~ '/welcome xyz:!@#$%^&*()|:;.,?/-.'; # (No need for any `\`)

.=subst: / <-:L -:N> /, { q:!b:s '$/' }, :g;

.say; # 42\!\@\#\%\^\|\|\/welcome\ xyz\:\!\@\#$\%\^\&\*\(\)\|\:\;\.\,\?\/\-\.

这只是不同衣服的相同解决方案。

我用过Q Langq。这默认为 '...' 字符串,如对其参数的解释。但是可以通过使用选项广泛地控制它的行为。我使用 :!b 选项来关闭解释 backslashes off,并使用 :s 来解释 scalar 变量(带有 $ 印记) on.

脚注

¹ 当然是模数优化。也就是说,我忽略了在语义上对用户代码不可见的优化(我之所以忽略它,正是因为它在语义上是不可见的)。这与我在之前的 SO 回答中引用的“保守电话”形成鲜明对比,我的意思是类似于 WONTFIX.

下面的代码 在每个 non-alphanumeric 字符前放置一个转义符号

my $b = '!@#%^||' ~ '/welcome xyz:!@#\$%^&*()|:;.,?/-.';
say $b.subst: / <?before <-alnum>> /, '\', :g
\!\@\#\%\^\|\|\/welcome\ xyz\:\!\@\#\$\%\^\&\*\(\)\|\:\;\.\,\?\/\-\.

如果 OP 已经考虑了以下内容,我们深表歉意:

如果您尝试在 Raku 中对 non-alnum 字符进行反斜杠转义的唯一原因是将结果放入变量中,然后通过 Raku 正则表达式进行测试,那么在您的字符串变量上调用 .raku 可以通常会有帮助(即它会让你 part-of-the-way 到那里):

~~$ echo '!@#%^||/welcome xyz:!@#$%^&*()|:;.,?/-.' | raku -ne '.raku.put'

Returns:

"!\@#\%^||/welcome xyz:!\@#\$\%^\&*()|:;.,?/-."

查看上面的结果,您会看到 backslash-escaping 的中间级别,反斜杠保护 $@%&\ 个字符。

您可以从结果字符串中删除周围的 double-quotes,如下所示:

~$ echo '!@#%^||/welcome xyz:!@#$%^&*()|:;.,?/-.' | raku -ne '.raku.comb(/\" <(.+)> \"/).put'
!\@#\%^||/welcome xyz:!\@#\$\%^\&*()|:;.,?/-.

...或者更异想天开的:

~$ echo '!@#%^||/welcome xyz:!@#$%^&*()|:;.,?/-.' | raku -ne '.raku.chop.flip.chop.flip.put'
!\@#\%^||/welcome xyz:!\@#\$\%^\&*()|:;.,?/-.