在每个非字母数字字符前加上转义符号。

10

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

 > 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/// 函数没有完成我想要实现的功能。

如何快速将字符串中每个非字母数字字符前面添加 "\" ? 看起来很简单,但实际上很困难。谢谢。

3个回答

8
以下代码字面上会在每个非字母数字字符前面添加一个转义符号。
my $b = '!@#%^||' ~ '/welcome xyz:!@#\\$%^&*()|:;.,?/-.';
say $b.subst: / <?before <-alnum>> /, '\\', :g

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

3
非常感谢你,wamba!简明扼要! - lisprogtor
1
正如您所知,<alnum>在Raku中包括下划线 _。因此,任何下划线 _ 都不会被您的解决方案反斜杠转义(这可能确实是@lisprogtor想要的)。 - jubilatious1
这让我想知道为什么新值中有双反斜杠\\ - 啊...一个单独的\转义了闭合的'。引号很棘手。我建议使用Q'\'来避免这个查询。 - librasteve

2

TL;DR 在一个代码块中包裹替换内容 ({ ... })。

$/subst 结合使用的问题

引用来自$/ 文档:

设置为最后一个正则表达式匹配的结果

这并不总是正确的。

引用源自我在一篇SO答案中的"Rakudo的匹配变量发布"部分(回复另一个你写的SO Q):

正则表达式/语法引擎对于[何时值得"发布"(更新)$/]做出了保守的调用。这里的"保守"意味着引擎通常避免进行发布,因为它会减慢速度且通常是不必要的。不幸的是,它有时太过于乐观,以至于实际上需要发布时无法正确预测。因此,需要程序员有时通过显式地插入代码块强制发布匹配变量...

上述文字的背景是你早期的问题,并不是subst的替换。我还没有阅读编译器代码来检查这个新问题的情况。

然而,当我阅读你的新SO Q时,我立刻感到相当自信,即在考虑到$/文档中关于“设置为最后一个正则表达式匹配的结果”的措辞,并在subst调用的上下文中进行时,如果传递给subst的替换只是一个字符串,那么更新$/不会发生


为了更详细地了解当你在代码块中包裹替换内容时发生了什么,可以使用一个不包裹$/但仍会"en passant"地执行say的代码块:

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

如您执行该代码,将会发现 $/ 的初始值为 Nil

然后,在该语句被执行但在下一个语句执行之前,$/ 的值得到了更新。这就是为什么在每个后续语句中都会获得不同(但仍然无用)的结果。也就是说,$/ 确实正在更新,但更新来得太晚了,如果您只是在字符串表达式中使用 $/ 而不是将其放在代码块中,它就不起作用了。
当在最新版本的Rakudo中使用 subst 时的解决方案
再次引用同一份文档:

每个例程都会创建一个新的 [$/]。

我没有检查编译器源代码,但感到相当有信心,即一个新的 $/ 不仅在每个 Routine 中创建,而且在每个 Block 中创建。
因此,我测试了将替换包装在代码块中,并确保匹配变量 "publication" (更新 $/ 等变量)确实已发生。
所以我认为这是一个解决方案。
另一个解决方案
什么是在字符串中在每个非字母数字字符之前放置“\”的快速方法?
$_ = '42!@#%^||' ~ '/welcome xyz:!@#$%^&*()|:;.,?/-.'; # (No need for any `\`)

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

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

这只是不同形式的相同解决方案。

我使用了Q Langq。这会默认将其参数解释为类似于'...'的字符串。但是,通过使用选项,可以广泛控制其行为。我使用了:!b选项关闭反斜杠的解释,并使用:s选项打开标量变量(带有$标记)的解释。

脚注

¹ 当然,除了优化。也就是说,我忽略了在用户代码中语义上不可见的优化(我之所以忽略它,正是因为它在语义上不可见)。这与我在先前的SO答案中讨论的“保守调用”形成了鲜明对比,我指的是类似于WONTFIX的东西。


0

如果下面的内容已经被提问者考虑过了,那我很抱歉:

如果你在 Raku 中尝试反斜杠转义非字母数字字符只是为了将结果存入变量并通过 Raku 正则表达式进行测试,那么在字符串变量上调用 .raku 通常会很有帮助(即它可以帮助你完成其中一部分):

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

返回:

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

从上面的结果可以看出,有一定程度的反斜杠转义,反斜杠保护了字符$@%&\

您可以按照以下方式从结果字符串中删除周围的双引号:

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

...或者稍微有些异想天开的:

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

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