数字索引转Excel列名
1. 说明: 数字转excel列名, 其实和10进制数字转26进制数字差不多, 只是由于excel列名的规则和普通26进制有一些区别,所以需要特殊处理一下。
2. 方法: 在excel中A对应数字1、Z对应数字26, 所以列名转数字其实是很直观的: 现将字母换成数字, 然后用26的幂次加权即可, 比如ABC -> [1, 2, 3] -> 1*26**2 + 2*26**1 + 3
, ZZ->[26, 26]-> 26 * 26**1 + 26
, 和26进制
不同的地方在于26进制
的系数是0-25
, 而这里的系数是1-26
。其实不管是什么情况, 只要写出了幂次表达式,就可以按照进制转换的方法很方便的改写代码, 这里的需要做的改动就是当%26
的余数为0时,需要将0变成26(因为没有系数0,只有系数26),同时将除数部分减1即可。
# 转换单个数字
def num_to_abc(num):
""" 给定索引num(1开始), 返回excel中对应的ABC列名, 此函数和进制转换不一样
excel列名和数字转换规则: A->1, Z->26, 系数是从1-26(不是0-25, 这是和26进制不一样的地方)
列名转数字: 先将每位的字母转成该位的数字, 如ABZ -> [1, 2, 26], 然后计算加权和, 1*26**2 + 2*26 + 26
数字转列名: 根据列名转数字的写法可知, 整体是按照进制转换去做, 但是需要处理余数为0时, 要改成26, 并让除数减1
ps: excel列名整体上来说就是进制转换, 唯一不同的是, 它的系数是1-26, 而不是0-25, 按照拆分后的带幂次数字去处理即可
"""
abc_num = ''
while num > 0:
d, r = num // 26, num % 26
if r == 0: # 当余数是0时, 此位的值要改成26, 这是和进制转换不同的地方
d, r = d - 1, 26
abc_num += chr(r + ord('A') - 1)
num = d
return abc_num[::-1]
# 转换一个范围内的数字
# 使用加法原则,后一个等于前一个加1,经测试此方法比用n次方法1在n=1e6时快1倍, 其实时间复杂度是一样的,只是方法1中有很多除法和取模运算。
def range_to_abc(start, end):
assert start > 0 and end > start
res_abcs = [num_to_abc(start)]
for i in range(start + 1, end):
prev_abc = res_abcs[i - start - 1][::-1]
cur_abc = ''
for j, c in enumerate(prev_abc):
if c < 'Z':
cur_abc += (chr(ord(c) + 1) + prev_abc[j + 1:])
break
cur_abc += 'A'
else:
cur_abc += 'A'
res_abcs.append(cur_abc[::-1])
return res_abcs