将数字转换为Excel的基数26

Yar*_*lav 3 python numbers base

好吧,我只看似简单的事情。我正在尝试将数字转换为以26为底的数字(即3 = C,27 = AA等)。我猜我的问题与模型中没有0有关?不确定。但是,如果运行代码,您将看到数字52、104,尤其是676附近的数字确实很奇怪。谁能给我一个关于我没看到的提示?我会很感激的。(以防浪费时间,@为ascii char 64,A为ascii char 65)

def toBase26(x):
    x = int(x)
    if x == 0:
        return '0'
    if x < 0:
        negative = True
        x = abs(x)
    else:
        negative = False
    def digit_value (val):
        return str(chr(int(val)+64))
    digits = 1
    base26 = ""
    while 26**digits < x:
        digits += 1
    while digits != 0:
        remainder = x%(26**(digits-1))
        base26 += digit_value((x-remainder)/(26**(digits-1)))
        x = remainder
        digits -= 1
    if negative:
        return '-'+base26
    else:
        return base26

import io    
with io.open('numbers.txt','w') as f:
    for i in range(1000):
        f.write('{} is {}\n'.format(i,toBase26(i)))
Run Code Online (Sandbox Code Playgroud)

因此,我通过对函数(在while循环中的2 if语句)进行了一些更改找到了一个临时的解决方法。无论如何,我的列数限制为500,对函数的以下更改似乎可以解决x = 676的问题,所以我很满意。但是,如果您找到任何x的通用解决方案(可能对我的代码可能有所帮助),那就太酷了!

def toBase26(x):
    x = int(x)
    if x == 0:
        return '0'
    if x < 0:
        negative = True
        x = abs(x)
    else:
        negative = False
    def digit_value (val):
        return str(chr(int(val)+64))
    digits = 1
    base26 = ""
    while 26**digits < x:
        digits += 1
    while digits != 0:
        remainder = x%(26**(digits-1))
        if remainder == 0:
            remainder += 26**(digits-1)
        if digits == 1:
            remainder -= 1
        base26 += digit_value((x-remainder)/(26**(digits-1)))
        x = remainder
        digits -= 1
    if negative:
        return '-'+base26
    else:
        return base26
Run Code Online (Sandbox Code Playgroud)

pok*_*oke 5

转换为Excel的“基数26”时出现的问题是Excel,AA实际上是一个数字,26 * 26**1 + 26 * 26**0而普通的基数26则1 * 26**2 + 1 * 26**1 + 0 * 26**0不能。因此,我们无法在此处使用常规方法来转换这些数字。

相反,我们必须滚动自己的divmod_excel函数:

def divmod_excel(n):
    a, b = divmod(n, 26)
    if b == 0:
        return a - 1, b + 26
    return a, b
Run Code Online (Sandbox Code Playgroud)

这样,我们可以创建一个to_excel函数:

import string
def to_excel(num):
    chars = []
    while num > 0:
        num, d = divmod_excel(num)
        chars.append(string.ascii_uppercase[d - 1])
    return ''.join(reversed(chars))
Run Code Online (Sandbox Code Playgroud)

从另一个方向来看,这有点简单

from functools import reduce
def from_excel(chars):
    return reduce(lambda r, x: r * 26 + x + 1, map(string.ascii_uppercase.index, chars), 0)
Run Code Online (Sandbox Code Playgroud)

这组函数可以正确执行以下操作:

>>> to_excel(26)
'Z'
>>> to_excel(27)
'AA'
>>> to_excel(702)
'ZZ'
>>> to_excel(703)
'AAA'
>>> from_excel('Z')
26
>>> from_excel('AA')
27
>>> from_excel('ZZ')
702
>>> from_excel('AAA')
703
Run Code Online (Sandbox Code Playgroud)

我们实际上可以通过简单地检查是否可以将它们链接起来以重现原始数字来确认它们彼此正确相反地工作:

for i in range(100000):
    if from_excel(to_excel(i)) != i:
        print(i)
# (prints nothing)
Run Code Online (Sandbox Code Playgroud)

  • @IMCoins 那个[是内置的](https://docs.python.org/3/library/functions.html#divmod)。 (2认同)