使用哈希的Ruby音译

Rud*_*koŭ 3 ruby

我尝试使用hash进行Cyrillic => Latin音译,我使用#coding:utf-8和ruby 1.9.3.我希望此代码更改值file_name.为什么这段代码file_name保持不变?

abc = Hash.new
abc = {"a" => "a", "b" => "?", "v" => "?", 'g' => "?", 'd'=> "?", 'jo' => "?", 'zh' => "?", 'th' => "?", 'i' => "?", 'l' => "?", 'm' => "?", 'n' => "?",'p' => "?", 'r' => "?", 's' => "?", 't' => "?", 'u' => "?", 'f' => "?", 'h' => "?", 'c' => "?", 'ch' => "?", 'sh' => "?", 'sch' => "?", 'y' => "?",'u' => "?", 'ja' => "?"} 
file_name.each_char do |c| 
     abc.each {|key, value| if c == value then c = key end }
end 
Run Code Online (Sandbox Code Playgroud)

Nei*_*ter 7

问题.each_char是块变量 - c在你的问题中 - 没有指向字符串中允许在原位改变字符串的字符.这里是你可以做从那里,每个字符映射工作方式(使用.map后跟一个.join为实例) -但它们是低效相比,.tr!或者.gsub!你的目的,因为打破了串出到字符数组,并重建它涉及到创建许多Ruby对象.

我想你需要做点什么

file_name.tr!( 'a??????????????????', 'abvgdilmnprstufhcyu' )
Run Code Online (Sandbox Code Playgroud)

它非常有效地涵盖了单个字母的转换.然后你有一些多字母转换.我会用gsub!它,你的哈希的反转副本

latin_of = {"?"=>"jo", "?"=>"zh", "?"=>"th", "?"=>"ch", 
            "?"=>"sh", "?"=>"sch", "?"=>"ja"}
file_name.gsub!( /[???????]/ ) { |cyrillic| latin_of[ cyrillic ] }
Run Code Online (Sandbox Code Playgroud)

注意,与each_char块不同,块的返回值.gsub!用于替换原始字符串中匹配的任何内容.上面的代码使用原始哈希的反转来快速找到匹配的西里尔字符的正确拉丁语替换.

你不需要tr!...相反,如果您愿意,只需使用第二种语法在一次传递中使用原始哈希的反转.使用两种方法的成本可能意味着你并没有真正从使用中获得那么多.tr!.但你应该了解String#tr!方法,它可以非常方便.


编辑:正如评论中所建议的,.gsub!可以在这里为你做更多的事情.假设latin_of是使用西里尔语键和拉丁语值的完整哈希,你可以这样做:

file_name.gsub!( Regexp.union(latin_of.keys), latin_of )
Run Code Online (Sandbox Code Playgroud)

有两点需要注意:

  • Regexp.union(latin_of.keys)正在采取一系列你想要转换的键,并确保gsub它们可以在中找到它们String

  • gsub! 接受散列作为第二个参数,并通过将其作为关键字并将其替换为关联值来转换每个匹配 - 正是您要查找的行为.

  • 你也可以说`gsub!(Regexp.union(latin_of.keys),latin_of)`并从映射表中驱动整个事情. (3认同)