2014-07-23 65 views
3

在電子表格中,我將單元格命名爲「F14」,「BE5」或「ALL1」。我有第一部分,列座標,在一個變量中,我想將其轉換爲基於0的整數列索引。如何將電子表格「letternamed」列座標轉換爲整數?

我該如何做,最好在Ruby中以優雅的方式進行操作?

我可以使用強力方法:我可以想象通過所有字母循環,將它們轉換爲ASCII並添加到結果中,但我覺得應該有更優雅/直接的東西。

編輯:示例:爲了簡化,我只談論列座標(字母)。因此,在第一種情況下(F14),我有「F」作爲輸入,我期望結果是5.在第二種情況下,我有「BE」作爲輸入,我期望得到56,對於我想要的「ALL」 999

+0

任何人都可以投票結束這個問題給我任何想法爲什麼建議它。這並不是最受歡迎的反應。我不知道有什麼理由,這肯定並不意味着我不會誤會。如果你不讓我知道我被拒絕的原因是什麼,我最有可能一遍又一遍地重複同樣的錯誤。感謝您考慮以更多的敘述方式與我溝通:) – gorn

+0

對於那些對這個問題本身感興趣的人 - 我嘗試過將某個字母部分視爲基於36的數字,並從中減去99A並將其轉換爲十進制(雖然它被視爲基於26的數字),它幾乎工作,但不完全。 – gorn

+0

我目前遇到的醜陋解決方案是'colname = colname.rjust(3,'@'); col =(colname [-1] .ord-64)+(colname [-2] .ord-64)* 26 +(colname [-3] .ord-64)* 26 * 26'其中colname是列座標。 – gorn

回答

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 

不幸的是目前ž字符,這將需要被解釋爲10(基臺26),所以我們需要一個小竅門。我們移動每個數字1更多然後需要,而不是添加它在最後(每個數字在原始名稱) `

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,因爲我認爲它使得代碼更具可讀性,但是如果你不喜歡這樣的事情,你可以將它們內聯或在其他地方定義它們。

+0

爲什麼最後有-1? – gorn

+0

將其變爲基於零的索引。如果你想要一個基於1的索引,你可以刪除 - 1. –

+0

@Tim_Destan是的,當然,對不起,這是明顯的 – gorn

0

我們可以使用模和輸入的長度。用最後一個字符 來計算確切的「位置」,剩下的要計數 我們在字母表中做了多少「圈數」,例如:

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。最好!

+0

謝謝你以我根本不認爲的方向採取這一點。 – gorn

+0

hmmmm ....代碼似乎不適合我。當用column_to_integer('F5')調用它時,我得到**未定義的方法'last'用於「A」:String **。順便說一句,我不明白你打算如何迭代名稱比一個字符長的列。 – gorn

+0

@gorn對不起,代碼現在已經修復。這個想法是將列名中的字母與'ALPHABET'匹配,並將它們分成一個數組,即AK14 - > [A,K]。基於這個數組'長度',我們計算'ALPHABET'上的迭代並使用'last'元素,我們找到了確切的'索引'位置,即[A,K]有2個元素,這意味着1圈(1 * 26)加上K(10)的位置,因此AK - > 26 + 10 = 36.有意義嗎? – wicz

相關問題