6

我正在用 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

如果这个要求看起来非常基本,我提前道歉。干杯!

4

5 回答 5

6

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

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

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

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

于 2012-11-25T23:17:18.433 回答
6

第二个调用不会覆盖第一个。第一次调用返回一个带有替换的副本@text,但您没有对该返回值做任何事情。如果要修改@text,则需要改为使用gsub!。如果您不想修改@text,则需要链接gsub调用。例如,如果你有来自slivu's answer的映射哈希,这将返回翻译后的文本,而无需实际修改@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....
于 2012-11-25T23:49:14.623 回答
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.

更新:正如马克所建议的,使用gsub!将避免多余的复制/分配操作:

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

这是一个工作演示

于 2012-11-25T23:30:54.743 回答
1

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

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

这比多次迭代要快得多gsub

于 2012-11-26T05:55:43.587 回答
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
于 2012-11-26T01:00:11.277 回答