

Rubyでアルファベットだけの26進数をつくりたいのですがどうしたらよいのでしょうか。

integer.to_s(26)  
にすると数字とアルファベットの組み合わせになってしまいます。


CC BY-SA 3.0
2015-02-07T05:47:19.730
6083
2015-02-18T05:36:56.227
2015-02-07T06:42:36.073
4114
5855
question
ruby
Rubyでアルファベットのみの26進数をつくりたい


`String#tr` で `tr("0-9a-p", "a-z")` としてはいかがでしょうか。

[code]

    0.to_s(26).tr("0-9a-p", "a-z")
    #=> "a"
    25.to_s(26).tr("0-9a-p", "a-z")
    #=> "z"
    26.to_s(26).tr("0-9a-p", "a-z")
    #=> "ba"
    
[/code]

個人的には 0 が a になるのはスゴく違和感があります^^;


CC BY-SA 3.0
2015-02-07T05:53:07.247
6084
2015-02-07T05:53:07.247
4114
6083
answer


INPUTとOUTPUTの例を示してもらえると助かります。  
特に桁が繰り上がるときの仕様がハッキリしていないと、お望みの回答が出てこない恐れがあります。

とりあえず、かなり昔に「Excel列名変換問題」と称してExcelと同じようなカラムの数え方（？）をするようなプログラムを書いたことがあります。  
実行例はこんな感じです。

[code]

    1 => A
    26 => Z
    27 => AA
    16384 => XFD
    
[/code]

昔に書いたコードなのでリファクタリングの余地は大きいと思いますが、参考までに載せておきます。

[code]

    class ExcelColConv
      AZ_LENGTH = 'Z'.ord - 'A'.ord + 1 #26
      OFFSET_NUM = 'A'.ord - 1 #64
    
      # 数字からアルファベット
      def to_col_string(col_num)
        convert_num '', col_num 
      end
    
      def convert_num(ret, n)
        if n == 0
          ret
        else
          quo, rem = excel_divmod n
          convert_num (rem + OFFSET_NUM).chr + ret, quo # 再帰           
        end
      end    
    
      def excel_divmod(n)
        quo, rem = n.divmod AZ_LENGTH
        rem == 0 ? [quo - 1, AZ_LENGTH] : [quo, rem]
      end
    end
    
    conv = ExcelColConv.new
    [1, 26, 27, 16384].each do |n|
      str = conv.to_col_string(n)
      puts "#{n} => #{str}"
    end
    
[/code]

この問題に関するブログも書いているので、よかったら読んでみてください。

[Excel列名変換問題をRubyとPerlとC#とF#で書いてみた](http://blog.jnito.com/entry/20111231/1325311566)


CC BY-SA 3.0
2015-02-07T10:08:54.837
6095
2015-02-07T10:08:54.837
85
6083
answer


単純に２６進変換するのを書いてみました。

[code]

    class Integer
        def to_26_a
            n = self
            if n == 0
                "a"
            else
                table = [*'a'..'z']
                result = ""
                while n > 0
                    result += table[n % 26]
                    n /= 26
                end
                result.reverse!
            end
        end
    end
    
    puts(0.to_26_a) #a
    puts(1.to_26_a) #b
    puts(25.to_26_a)#z
    puts(26.to_26_a)#ba
    
[/code]


CC BY-SA 3.0
2015-02-07T10:11:04.220
6096
2015-02-07T10:17:06.450
2015-02-07T10:17:06.450
5044
5044
6083
answer


Excel列名変換問題 試験会場がこちらと聞いて。

[code]

    class Fixnum
      def bijective_s(base=nil, offset=nil)
        offset ||= 'A'.ord #65
        base ||= 26
        value = self
        result = []
        while value > 0
          value -= 1
          result << (value%base+offset).chr
          value /= base
        end
        result.reverse.join
      end
    end
    
[/code]

0.bijective_s #=> ""  
1.bijective_s #=> "A"  
26.bijective_s #=> "Z"  
27.bijective_s #=> "AA"  
53.bijective_s #=> "BA"  
702.bijective_s #=>"ZZ"  
703.bijective_s #=>"AAA"

いや。再帰をケチっただけなんですがね。


CC BY-SA 3.0
2015-02-17T08:36:45.737
6631
2015-02-17T08:36:45.737
8335
6083
answer


関数で実装すると以下のようになります。

[code]

    def dec26(num)
      table = ('a'..'z').to_a
      num > 25 ? dec26(num/26)+table[num%26] : table[num%26]
    end
    
[/code]

しかし、上記の方法だと再帰するたびにtableがスタックに積み上げられるため、以下のほうが負荷が少ないです。

[code]

    def dec26(num)
      (num > 25 ? dec26(num / 26) : '') + ('a'.ord + num % 26).chr
    end
    
[/code]


CC BY-SA 3.0
2015-02-18T00:29:55.067
6656
2015-02-18T05:36:56.227
2015-02-18T05:36:56.227
4114
8351
6083
answer