在电子表格中,我有一些名为“F14”,“BE5”或“ALL1”的单元格。我在变量中有第一部分,列坐标,我想将它转换为基于0的整数列索引。
我如何在Ruby中以优雅的方式做到这一点?
我可以使用强力方法来实现:我可以设想循环遍历所有字母,将它们转换为ASCII并添加到结果中,但我觉得应该有更优雅/更直接的东西。
编辑:示例:为了简化,我只讨论列坐标(字母)。因此在第一种情况下(F14)我有“F”作为输入,我希望结果为5.在第二种情况下,我有“BE”作为输入,我期望得到56,因为“ALL”我想得到999。
答案 0 :(得分:3)
不确定这是否比您已有的代码更清晰,但它确实具有处理任意数量字母的优势:
class String
def upcase_letters
self.upcase.split(//)
end
end
module Enumerable
def reverse_with_index
self.map.with_index.to_a.reverse
end
def sum
self.reduce(0, :+)
end
end
def indexFromColumnName(column_str)
start = 'A'.ord - 1
column_str.upcase_letters.map do |c|
c.ord - start
end.reverse_with_index.map do |value, digit_position|
value * (26 ** digit_position)
end.sum - 1
end
我已经为String
和Enumerable
添加了一些方法,因为我认为它使代码更具可读性,但如果你不喜欢那种东西,你可以内联这些或在别处定义它们
答案 1 :(得分:1)
我们可以使用modulo和输入的长度。最后一个角色会 用于计算确切的“位置”,以及要计算的余数 我们在字母表中做了多少“圈”,例如
def column_to_integer(column_name)
letters = /[A-Z]+/.match(column_name).to_s.split("")
laps = (letters.length - 1) * 26
position = ((letters.last.ord - 'A'.ord) % 26)
laps + position
end
使用十进制表示(ord
)和数学技巧似乎很整洁
解决方案起初,但它有一些关于的问题的痛点
实现。我们都有幻数,26
和常数'A'.ord
结束了。
一个解决方案是让我们的代码更好地了解我们的域名,即 字母表。在这种情况下,我们可以使用的位置切换模数 字母中的最后一个字符(因为它已经在基于零的数组中排序),例如
ALPHABET = ('A'..'Z').to_a
def column_to_integer(column_name)
letters = /[A-Z]+/.match(column_name).to_s.split("")
laps = (letters.length - 1) * ALPHABET.size
position = ALPHABET.index(letters.last)
laps + position
end
最终结果:
> column_to_integer('F5')
=> 5
> column_to_integer('AK14')
=> 36
HTH。最好!
答案 2 :(得分:0)
我发现这种转换特别简洁:
def index_from_column_name(colname)
s=colname.size
(colname.to_i(36)-(36**s-1).div(3.5)).to_s(36).to_i(26)+(26**s-1)/25-1
end
解释原因
(警告扰乱;)提前)。基本上我们这样做
(colname.to_i(36)-('A'*colname.size).to_i(36)).to_s(36).to_i(26)+('1'*colname.size).to_i(26)-1
用简单的英语表示我们将colname解释为26个碱基数。在我们能够做到这一点之前,我们需要将所有的A解释为1,将B解释为2等。如果只需要它,那就更简单了,即
(colname.to_i(36) - '9'*colname.size).to_i(36)).to_s(36).to_i(26)-1
不幸的是,存在Z字符需要被解释为10(基数为26),所以我们需要一个小技巧。我们将每个数字移动1个以上,然后将其添加到最后(对于原始colname中的每个数字) `