【问题标题】:Using Ruby gsub with regex as replacement使用带有正则表达式的 Ruby gsub 作为替换
【发布时间】:2020-08-29 15:53:47
【问题描述】:

Ruby gsub 支持使用正则表达式作为模式来检测输入 并且它也可以允许使用匹配组号替换

例如,如果这是一个正则表达式检测任何单词开头的小写字母,并在其前放置一个x,在其后放置一个y 这将给出完美的结果:

"testing gsub".gsub(/(?<=\b)[a-z]/,'x\0y')
#=> "xtyesting xgysub"

但如果我想使用正则表达式将此匹配组转换为大写 在正常的正则表达式中,通常可以做到这一点\U\$0 解释为here

不幸的是,当我这样尝试时:

"testing gsub".gsub(/(?<=\b)[a-z]/,'\U\0')
#=> "\\Utesting \\Ugsub"

另外,如果我尝试在替换字段中使用原始正则表达式,如下所示:

"testing gsub".gsub(/(?<=\b)[a-z]/,/\U\0/)`

我收到类型错误:

TypeError (no implicit conversion of Regexp into String)

我完全知道使用这样的地图可以选择:

"testing gsub".gsub(/(?<=\b)[a-z]/,&:upcase)

但不幸的是,规则(模式、替换)是从 .yaml 文件加载的,它们以这种方式应用于字符串:

input.gsub(rule['pattern'], rule['replacement'])

我无法将 &amp;:upcase 存储在 .yaml 中以作为原始字符串

我可能会做的解决方法是检测大写字母是否是替换的“大写字母” 并这样做

"testing gsub".gsub(/(?<=\b)[a-z]/) {|l| l.send("upcase")}

但我不想修改这个逻辑:

input.gsub(rule['pattern'], rule['replacement'])

如果有一种解决方法可以在 gsub 替换中使用正则表达式,或者在 YAML 中存储诸如 &amp;:upcase 之类的方法而不作为字符串加载,那将是完美的。

谢谢!

【问题讨论】:

  • 恐怕不可能。根据文档,替换“可能包含对 \\d 形式的模式捕获组的反向引用,其中 d 是组号”。只有数字,没有字母或特殊字符。它与 Perl 的 gsub 替换逻辑不兼容。
  • (?&lt;=\b)[a-z] 应该写成\b[a-z]。而且由于不支持\U,因此无法以您想要的方式解决您的问题。
  • 谢谢你们的回答,我想可能有人知道我遗漏了一些东西,再次感谢@WiktorStribiżew 我想匹配字母,也不想匹配边界,所以我想我应该使用lookbehind 来匹配字符但是,是的,我想它会给出相同的结果

标签: regex ruby yaml gsub


【解决方案1】:

TL;DR

你不能做什么你想要的方式。这记录在 Onigmo 源代码中。您必须使用不同的方法,或重构代码的其他区域来模拟您想要的行为。

\U 这样的转义在 Ruby 中不可用

\U 这样的特殊转义是 GNU sed 的扩展或从 PCRE 库移植。它们不是 Ruby 当前正则表达式引擎的一部分。 Onigmo source 明确提到缺少这些转义:

A-3. Missing features compared with perl 5.18.0

   + \N{name}, \N{U+xxxx}, \N
   + \l,\u,\L,\U, \C
   + \v, \V, \h, \H
   + (?{code})
   + (??{code})
   + (?|...)
   + (?[])
   + (*VERB:ARG)

其他方法

您可以通过多种不同的方式做您想做的事,例如使用String#gsub 的块形式在每场比赛中调用String#upcase。例如:

"testing gsub".gsub(/\b\p{Lower}+/) { |m| m.upcase }
#=> "TESTING GSUB"

如果您想可靠地引用某些匹配变量,例如 $&amp;$1,您还必须使用块形式,因为这些变量可能会引用先前匹配的文本。为了说明,请考虑:

"foo bar".gsub /\b\p{Lower}+/, "#{$&.upcase}"
#=> "BAR BAR"

由于这主要是一个 X/Y 问题,如果您发布一个相关问题,其中包含您的 YAML 源示例和您当前用于解析正则表达式匹配/替换的代码,您可能会对收到的答案更满意。也许有一种方法可以包装或重构您没有考虑过的代码,但您无法以您想要的方式解决这个问题。

【讨论】:

  • 感谢您回答我的问题,如果帖子太长,请见谅。但是,如果你继续一点,我提到了这个input.gsub(rule['pattern'], rule['replacement']),代表我从 YAML 文件中获取模式和替换的代码段,还有这个"testing gsub".gsub(/(?&lt;=\b)[a-z]/) {|l| l.send("upcase")},它几乎与第一个提议的方法相同
  • 最后,最后一种方法 LGTM,但不幸的是,当它立即使用时,它会失败,就我而言,$& 与之前的匹配正确,但就像 "foo bar".gsub /\b\p{Lower}+/, "#{$&amp;.upcase}" #=&gt; NoMethodError (undefined method 'upcase' for nil:NilClass) 以来输出还没有。如果您将操作分为两行代码,也许它会起作用再次感谢您的帮助,非常感谢
猜你喜欢
  • 1970-01-01
  • 2013-12-09
  • 1970-01-01
  • 2015-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-22
  • 1970-01-01
相关资源
最近更新 更多