在Ruby中使用'gsub'的许多实例

时间:2012-11-25 23:09:17

标签: ruby

我正在Ruby(1.9.3)中创建一个基本的翻译器。我从一个本地测试文件('a.txt')中提取并使用gsub替换某些匹配来模仿从当代英语到中/早现代英语的翻译。我遇到了可读性问题:

如何让大量的gsub使用更容易阅读?我试图使用以

开头的多行
def translate 
  @text.gsub(/my/, 'mine')
  @text.gsub(/\sis\s/, ' be ')
end

但这仅打印最终的gsub。我只能假设第二个请求会覆盖第一个请求。我想避免创建一个巨大的gsub请求行,我似乎无法找到合适的答案。

以下是我当前节目的一个示例:

lines = File.readlines('a.txt')
@text = lines.join

def translate 
  @text.gsub(/my/, 'mine').gsub(/\sis\s/, ' be ').gsub(/y\s/, 'ye ').gsub(/t\s/, 'te ').gsub(/t\,/, 'te,').gsub(/t\./, 'te.')
end

puts translate

如果此请求看起来非常基本,我会提前道歉。 干杯!

5 个答案:

答案 0 :(得分:6)

String#gsub方法返回完成替换的字符串的新副本,保留原始字符串不变。第一个示例中的两个替换都已完成,但第一个示例的结果将被丢弃,因为它未分配给任何内容。作为方法的结果返回第二个的结果。

如果您改为使用#gsub!方法,则会使用替换结果修改原始字符串,从而可以更轻松地进行多次替换。

def translate 
  @text.gsub!(/my/, 'mine')
  @text.gsub!(/\sis\s/, ' be ')
  @text
end

如果您不想修改对象上的属性,可以使用text = @text.dup启动该方法,然后使用text变量代替@text属性该方法的其余部分。

答案 1 :(得分:6)

第二个电话不会覆盖第一个电话。第一个调用返回@text的副本并进行替换,但是您没有对该返回值执行任何操作。如果您想修改@text,则需要使用gsub!。如果您不想修改@text,则需要链接gsub来电。例如,如果你有来自slivu's answer的映射Hash,这将返回翻译的文本,而不实际修改@text实例变量:

def translate
  RegexMap.inject(@text) do |string, mapping|
    string.gsub(*mapping)
  end
end

每个映射调用一次传递给inject的块(RegexMap中的键/值对)。第一次,string是传递给inject的值 - 即@text。之后,每个后续调用都会获得作为其string值传入的上一个调用的返回值。所以就好像你这样做了,但是这套映射更容易配置:

@text.gsub(/my/,'mine').gsub(/\sis\s/, ' be ').gsub(/y\s/,'ye ').gsub....

答案 2 :(得分:5)

更具可读性?

你会考虑建立一个地图并在其上使用循环吗?

RegexMap = {
  /my/     => 'mine',
  /\sis\s/ => ' be ',
  /y\s/    => 'ye ',
  /t\s/    => 'te ',
  /t\,/    => 'te,',
  /t\./    => 'te.',
}
text = '123 my 456 is 123y 456t 123t, 456t.'
RegexMap.each_pair {|f,t| text = text.gsub(f, t)}
puts text

#=> 123 mine 456 be 123ye 456te 123te, 456te.
Mark建议

更新,使用gsub!将避免冗余的复制/分配操作:

RegexMap.each_pair {|f,t| text.gsub! f, t}

Here is a working demo

答案 3 :(得分:0)

建立slivu的想法,这是一个类似Perl的选择:

@text = '123 my 456 is 123y 456t 123t, 456t.'

def s(regex, string)
   @text.gsub!(regex, string)
end

s /my/, 'mine'
s /\sis\s/, ' be '
s /y\s/, 'ye '
s /t\s/, 'te '
s /t\,/, 'te,'
s /t\./, 'te.'

puts @text

答案 4 :(得分:0)

如果你总是转换一个特定的模式,即单词,那么你可以有一个简单的匹配模式,然后根据单词替换每个匹配模式只需一次gsub

def translate 
  @text
  .gsub(/[ \t]+/, " ")
  .gsub(/\w+/,
    "my" => "mine",
    "is" => "be",
    "y" => "ye",
    "t" => "te"
  )
end

这比gsub多次迭代要快得多。