我正在处理的应用程序从许多外部来源获取加拿大地址并映射它们。一个非常罕见的映射错误来源是邮政编码中的数据输入错误,即输入大写o而不是0,大写i而不是1,依此类推。
出于此问题的目的,假设所有邮政编码数据都已删除所有空格,已大写,并且如果长度超过则截断为6个字符。在这种情况下,有效的加拿大邮政编码将采用“A1A1A1”格式。什么是优雅的方式来进行上述替换?
我们有一个有效的解决方案,但这已经成为我们办公室里一个有趣的问题,只是为了看看人们想出了什么。到目前为止,没有任何东西能够“令人敬畏”。
其他一些条件:
答案 0 :(得分:3)
def clean_postal_code
swaps = {'L' => '1', 'O' => '0'} #fill with whatever necessary substitutions
pc = self.postal_code
(pc.size/2).times do |n|
swaps.each do |letter, number|
pc[n*2+1] = pc[n*2+1].chr.gsub(letter, number) #only want numbers on odd indices
pc[n*2] = pc[n*2].chr.gsub(number, letter) #only characters on even indices
end
end
self.postal_code = pc
end
答案 1 :(得分:3)
与Tron相似,但(恕我直言)更简单,并且不需要数字到字母的地图是对称的:
chars = { '0' => 'O', '1' => 'I' } # etc.
nums = { 'O' => '0', 'I' => '1', 'Q' => '0' } # etc.
maps = [
->(c) { chars[c.upcase] || c.upcase },
->(c) { nums[ c.upcase] || c }
]
clean = (0 ... input.length).map { |i| maps[i % 2].call(s[i]) }.join
您从脏input
开始,并以clean
作为修正版本。例如,这会将'aib100'
转换为'A1B1O0'
。
如果需要,你可以将它包装在一个函数中:
def unmangle(input)
chars = { '0' => 'O', '1' => 'I' } # etc.
nums = { 'O' => '0', 'I' => '1', 'Q' => '0' } # etc.
maps = [
->(c) { chars[c.upcase] || c.upcase },
->(c) { nums[ c.upcase] || c }
]
(0 ... input.length).map { |i| maps[i % 2].call(input[i]) }.join
end
clean = unmangle('aib100')
# 'A1B1O0'
您也可以使用此(或其他各种类似的结构):
(0 ... input.length).inject(input) { |s, i| s[i] = maps[i % 2].call(s[i]); s }
如果您不喜欢map
/ join
版本。
答案 2 :(得分:1)
我认为这有点像一样紧凑,你可以使代码挑战。我不一定真的这样写 - 像Tron的回答可能更容易维护。
那就是说,这样的事情原则上应该起作用:
def clean_pc(pc)
pc.split(/(?<=\G..)/).map {|a| a[0].tr('01','OL') + a[1].tr('OoLliI','001111') }.join
end
(UPDATE)
...或者,更容易阅读,并且可能足以维持生产使用:
def clean_pc(pc)
pc.chars.each_slice(2).map {|a| a[0].tr('01','OL') + a[1].tr('OoLliI','001111')}.join
end