如何将电子表格“letternamed”列坐标转换为整数?

时间:2014-07-23 21:13:02

标签: ruby string data-conversion

在电子表格中,我有一些名为“F14”,“BE5”或“ALL1”的单元格。我在变量中有第一部分,列坐标,我想将它转换为基于0的整数列索引。

我如何在Ruby中以优雅的方式做到这一点?

我可以使用强力方法来实现:我可以设想循环遍历所有字母,将它们转换为ASCII并添加到结果中,但我觉得应该有更优雅/更直接的东西。

编辑:示例:为了简化,我只讨论列坐标(字母)。因此在第一种情况下(F14)我有“F”作为输入,我希望结果为5.在第二种情况下,我有“BE”作为输入,我期望得到56,因为“ALL”我想得到999。

3 个答案:

答案 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

我已经为StringEnumerable添加了一些方法,因为我认为它使代码更具可读性,但如果你不喜欢那种东西,你可以内联这些或在别处定义它们

答案 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中的每个数字) `