Ruby多字符串替换


75
str = "Hello☺ World☹"

预期输出为:

"Hello:) World:("

我可以做这个: str.gsub("☺", ":)").gsub("☹", ":(")

还有其他方法可以让我在单个函数调用中完成此操作吗?就像是:

str.gsub(['s1', 's2'], ['r1', 'r2'])

1
您为什么要一次通话就这样做?我宁愿坚持使用您的第一个解决方案。
2011年

2
@Semyon:映射表对很大,或者可以在运行时进行配置。
亩太短了

1
类似地,如果您最终拥有一个巨大的映射表,则基本上是在寻找一种模板语言。在这种情况下,您可以将其转换为DSL并为此编写一个解释器(或编译器)。
斯旺南德

我原本希望String#tr做到这一点,但是替换为多个字符意味着我不能使用它。
Andrew Grimm

Answers:


123

从Ruby 1.9.2开始,将String#gsubhash作为第二个参数替换为匹配的键。您可以使用正则表达式来匹配需要替换的子字符串,并为要替换的值传递哈希值。

像这样:

'hello'.gsub(/[eo]/, 'e' => 3, 'o' => '*')    #=> "h3ll*"
'(0) 123-123.123'.gsub(/[()-,. ]/, '')    #=> "0123123123"

在Ruby 1.8.7中,您可以使用一个块来实现相同的目的:

dict = { 'e' => 3, 'o' => '*' }
'hello'.gsub /[eo]/ do |match|
   dict[match.to_s]
 end #=> "h3ll*"

哇!我不知道!好东西!
kikito 2011年

酷,对此一无所知。一种更好的Perl版本tr
Marnen Laibow-Koser 2011年

请注意,这与在哈希的每个元素上调用str.gsub(key,value)不同。如果某些内容与正则表达式匹配,但哈希中没有条目,则将其删除。
Sprachprofi 2013年

3
@NarenSisodiya,实际上应该是:'(0)123-123.123'.gsub(/[()\-,.]/,'')您需要在'-'处添加转义字符。
jpbalarini 2015年

是的,那一行是错误的:'(0)123-123.123'.gsub(/[((--..]/,''))您需要转义破折号或将其移到前面。
格雷格·布拉斯

40

设置映射表:

map = {'☺' => ':)', '☹' => ':(' }

然后构建一个正则表达式:

re = Regexp.new(map.keys.map { |x| Regexp.escape(x) }.join('|'))

最后,gsub

s = str.gsub(re, map)

如果您被困在1.8土地上,那么:

s = str.gsub(re) { |m| map[m] }

如果Regexp.escape要替换的任何内容在正则表达式中具有特殊含义,则需要使用in。或者,多亏了steenslag,您可以使用:

re = Regexp.union(map.keys)

报价将为您服务。


@steenslag:这是一个很好的修改。
亩太短了

String#gsub接受字符串作为模式参数:“模式通常是一个Regexp;如果以字符串形式给出,则其包含的任何正则表达式元字符都将按字面意义进行解释,例如'\\ d'将匹配一个反冲,后跟'd' ,而不是数字。”。
安德鲁·格林

@Andrew:是的,但是我们要替换多个字符串,因此是正则表达式。
亩太短了

如果映射的键是正则表达式怎么办?替换似乎无效
content01 2014年

@ content01:在我的头顶上,我认为在这种情况下,您必须一个一个地走:map.each { |re, v| ... }
亩太短

37

您可以执行以下操作:

replacements = [ ["☺", ":)"], ["☹", ":("] ]
replacements.each {|replacement| str.gsub!(replacement[0], replacement[1])}

可能有一个更有效的解决方案,但这至少使代码更简洁


2
不是replacements.each吗?
DanneManne

4
这只是更加复杂和缓慢。
texasbruce

1
返回值each是被调用的集合。stackoverflow.com/questions/11596879/...
弥敦道马努索斯

1
使其返回结果且不更改str:replacements.reduce(str){|str,replacement| str.gsub(replacement[0],replacement[1])}
artm

4
您也可以使用@artmreplacements.inject(str) { |str, (k,v)| str.gsub(k,v) }并避免这样做[0][1]
Ben Lings

19

晚了聚会,但是如果您想用一个字符替换某些字符,可以使用正则表达式

string_to_replace.gsub(/_|,| /, '-')

在此示例中,gsub用下划线(-)替换了下划线(_),逗号(,)或()。


4
这样会更好:string_to_replace.gsub(/[_- ]/, '-')
Automatico

5

以下是另一种简单易懂的方法:

str = '12 ene 2013'
map = {'ene' => 'jan', 'abr'=>'apr', 'dic'=>'dec'}
map.each {|k,v| str.sub!(k,v)}
puts str # '12 jan 2013'

5

您也可以使用tr一次替换字符串中的多个字符,

例如,将“ h”替换为“ m”,将“ l”替换为“ t”

"hello".tr("hl", "mt")
 => "metto"

看起来比gsub简单,整洁且速度更快(尽管差别不大)

puts Benchmark.measure {"hello".tr("hl", "mt") }
  0.000000   0.000000   0.000000 (  0.000007)

puts Benchmark.measure{"hello".gsub(/[hl]/, 'h' => 'm', 'l' => 't') }
  0.000000   0.000000   0.000000 (  0.000021)

1

嘲笑上面的纳伦的答案,我会去

tr = {'a' => '1', 'b' => '2', 'z' => '26'}
mystring.gsub(/[#{tr.keys}]/, tr)

因此 'zebraazzeebra'.gsub(/[#{tr.keys}]/, tr)返回 “ 26e2r112626ee2r1”

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.