Kei Minagawa's Blog

皆川圭(@keimina)のブログ、Pythonで試したことを書いていきます

エクセルの列を表すアルファベットを数値に、または数値をエクセルの列を表すアルファベットに変換する話

以前の記事で、エクセルの列を表すアルファベットを数値に変換するプログラムを書いたのですが、今回は、その逆変換つまり、数値をエクセルの列を表すアルファベットに変換してみようと思います。

————————
※2018/11/15追記
数値をエクセルの列を表すアルファベットに変換する関数については こちらのに記載されているものより、処理速度、保守性においてはるかに優れたコードがあります。以下のURLに記載しましたので、数値をエクセルの列を表すアルファベットに変換する場合は以下のURLを参考にしてください。
keimina.hatenablog.jp

————————

いつも通り、プログラミング言語Python で行います。
今回は、おもいっきり横着してメモリーを大量消費する辞書を生成して無理やりやってみます。
そして最後に、作成した関数があっているかテストします。

まず、以前のコードをおさらいです。
数値をアルファベットに変換するコードは以下のようなものでした。

def conv(alphabet):
    total = 0
    for n, i in enumerate(alphabet[::-1]):
        chr_num = ord(i.lower())
        chr_A_num = ord('a')
        total +=  (1 + chr_num - chr_A_num)* (26**n)
    return total

この関数を使用するとアルファベットと数値の対応関係が得られます。
今回はこれを利用し、4文字までのアルファベットAからZZZZをこの関数に入力し対応関係を辞書として保存します。
これにより、制限付きですが、逆関数となる辞書が求まります。
制限はアルファベット4文字までということです。
それでも約47万列を表現できるため、実用上問題となる可能性は低いと思われます。

これをクラスで以下のようにまとめてみました。
使い方は、クラスのdocstringの使用方法の欄を参照してください。

class ExcelTool(object):
    '''
    注意:
    メモリを大量に消費するので注意してください。
    47万列までしか対応しません。
    初回インスタンス生成時に47万回計算する。そのためインスタンス生成に時間がかかる。
    インスタンスを生成した後に、変換用のメソッドを呼び出せる。

    使用方法:
    >>> # 最初に必ずインスタンスを作成する
    >>> et = ExcelTool()

    >>> # エクセルの列を表すアルファベットを数値に変換する
    >>> et.excel_alphabets_to_num("AA")
    27
    
    >>> # 数値をエクセルの列を表すアルファベットに変換する
    >>> et.num_to_excel_alphabets(27)
    27
    '''
    def __init__(self):
        from itertools import product
        self.alphabets = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' #"".join(chr(i) for i in range(65, 91))
        # 1-4文字のアルファベット作成し、数値に変換し、逆変換用の辞書を作る
        self.map_dict = {}
        for i in range(1, 5):
            self.map_dict.update({
                self.excel_alphabets_to_num("".join(alphabet_combination)): "".join(alphabet_combination)
                for alphabet_combination in product(self.alphabets, repeat=i)})
            
    def excel_alphabets_to_num(self, alphabet_combination):
        '''
        説明:
            エクセルの列を表すアルファベットを数値に変換する関数
        引数: str
            エクセルの列を表すアルファベットの文字列(大文字小文字は関係ない)
        戻り値: int
            アルファベットに対応する数値
        '''
        total = 0
        char_A = ord('A')
        for n, i in enumerate(alphabet_combination[::-1]):
            total +=  (1 + ord(i.upper()) - char_A)* (26**n)
        return total
    
    def num_to_excel_alphabets(self, num):
        '''
        説明:
            数値をエクセルの列を表すアルファベットに変換する関数
        引数: int
            エクセルの列を表すアルファベットに変換するための数値
        戻り値: str
            引数で与えた整数値に対応するエクセルの列を表すアルファベットの文字列
            文字列は常に大文字で返す。
        '''
        return self.map_dict[num]


###################################
# 以下はテストのためのコード
###################################

# はじめにインスタンスを作成する
et = ExcelTool()

print("テスト")
print("======== 数値からアルファベット========")
print("1               =>", et.num_to_excel_alphabets(1))
print("26              =>", et.num_to_excel_alphabets(26))
print("26*26+1(677)    =>", et.num_to_excel_alphabets(26*26+1))
print("26*26+26(702)   =>", et.num_to_excel_alphabets(26*26+26))
print("26*26+26+1(703) =>", et.num_to_excel_alphabets(26*26+26+1))

print("======== アルファベットから数値========")
print("A               =>", et.excel_alphabets_to_num('A'))
print("Z               =>", et.excel_alphabets_to_num('Z'))
print("ZA              =>", et.excel_alphabets_to_num('ZA'))
print("ZZ              =>", et.excel_alphabets_to_num('ZZ'))
print("AAA             =>", et.excel_alphabets_to_num('AAA'))

以下にテストの結果を載せます。
テストの結果:

テスト
======== 数値からアルファベット========
1               => A
26              => Z
26*26+1(677)    => ZA
26*26+26(702)   => ZZ
26*26+26+1(703) => AAA
======== アルファベットから数値========
A               => 1
Z               => 26
ZA              => 677
ZZ              => 702
AAA             => 703

以上になります。