Interpretando numeração de colunas à là Excel

Pois bem, hoje precisei converter índices comuns de um vetor (0, 1, 2…) em uma visualização à là Excel (A, B, C…). No início, fui pra solução mais simples:

def to_excel_col(n)
  ('A'..'Z").to_a[n]
end

Serviu pro basicão, mas e quando a planilha tiver mais de 26 colunas? Tive que aumentar o algoritmo:

def to_excel_col(n)
  unless defined? @serie
    az = ('A'..'Z').to_a
    @serie = az + az.map {|x| az.map {|y| x+y } }.flatten
  end
  @serie[n]
end

Resolveu pra até 702 colunas, mas e se for mais? E todo esse espaço de memória ocupado? Estava uma solução muito lazy, que tal usar um pouco de matemática?

def to_excel_col(n)
  @@az ||= ('A'..'Z').to_a
  (n >= 26 ? to_excel_col((n / 26) - 1) : '') + @@az[n % 26]
end

Divertido… Que tal fazer o inverso também? E que tal embutir nas classes adequadas, pra usarmos coisas legais como i.to_excel_col?

class Fixnum
  # Função recursiva para gerar numeração de colunas no formato Excel
  # (0 = A, 1 = B, 2 = C, ... 26 = AA, 27 = AB, 28 = AC)
  def to_excel_col
    @@az ||= ('A'..'Z').to_a
    (self >= 26 ? ((self / 26) - 1).to_excel_col : '') + @@az[self % 26]
  end

class String
  # Função recursiva para traduzir uma numeração de colunas no formato Excel para inteiro
  # (A = 0, B = 1, C = 2, ... AA = 26, AB = 27, AC = 28)
  def excel_col_to_i
    u = upcase
    return nil if u =~ /[^A-Z]/
    u.each_char.map{|c| c[0] - ?A}.reduce(nil) {|v,i| (v.nil? ? 0 : (v+1)*26) + i}
  end
end

Legal… E o algoritmo anterior ainda serve de Testcase!

test "works with up to 3 letters" do
  az = ('A'..'Z').to_a
  serie = az +
      az.map {|x| az.map {|y| x+y } }.flatten +
      az.map {|x| az.map {|y| az.map {|z| x+y+z } } }.flatten

  letras = az.count
  combinacoes = letras.power!(3) + letras.power!(2) + letras.power!(1)

  letras.should == 26 # teste de sanidade, são realmente 26 letras?
  0.upto(combinacoes-1).each do |n|
    # testa todas as combinações
    v = n.to_excel_col # converte o valor para "excel col"
    i = v.excel_col_to_i # converte de volta em inteiro
    v.should == serie[n]
    i.should == n
  end
end

3 comentários em “Interpretando numeração de colunas à là Excel

  1. Muito afude, agora só falta faze um que faz o imposto de renda sozinho😀
    mais legal ainda se puder fazer assim:
    “michel”.to_declaracao_de_imposto_de_renda

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s