我正在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
如果此请求看起来非常基本,我会提前道歉。 干杯!
答案 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}
答案 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
多次迭代要快得多。