问题描述
Ruby gsub支持使用正则表达式作为模式来检测输入 并且还可能允许在替换中使用匹配组号
例如,如果这是一个正则表达式,则在任何单词的开头都检测到小写字母,并在其前面放置x
,在其后面放置y
这样会产生完美的结果:
"testing gsub".gsub(/(?<=\b)[a-z]/,'x\0y')
#=> "xtyesting xgysub"
但是如果我想使用正则表达式将此匹配组转换为大写 在正常的正则表达式中,通常可以按照here
的说明进行此操作\U\$0
不幸的是,当我这样尝试时:
"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'])
并且我无法将&:upcase
存储在.yaml中作为原始字符串
我可以采取的解决方法是检测大写替换是否为“大写” 并以此方式
"testing gsub".gsub(/(?<=\b)[a-z]/) {|l| l.send("upcase")}
但我不想修改此逻辑:
input.gsub(rule['pattern'],rule['replacement'])
如果有一种解决方法,可以在gsub
替换中使用正则表达式,或者将&:upcase
之类的方法存储在YAML中而不以字符串形式加载,那么这将是完美的选择。
谢谢!
解决方法
TL; DR
您无法想要做什么。这在Onigmo来源中有记录。您将必须使用其他方法,或重构代码的其他区域以模拟所需的行为。
像\U
这样的转义在Ruby中不可用
特殊的转义,例如\U
是PCRE库中对sed或移植的GNU的扩展。它们不是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"
如果您要可靠地引用某些匹配变量,例如$&
或$1
,则还必须使用块形式,因为否则这些变量可能引用以前匹配中的文本。为了说明,请考虑:
"foo bar".gsub /\b\p{Lower}+/,"#{$&.upcase}"
#=> "BAR BAR"
由于这主要是一个X / Y问题,如果您发布相关问题并附上您的YAML源代码示例以及当前用于解析正则表达式匹配项/替换项的代码,则您可能会更满意收到的答案。也许有一种方法可以包装或重构您尚未考虑的代码,但是您将无法以所需的方式解决此问题。