22

这是在提供行和列 ID 时提供 COLUMN 名称的代码,但是当我给出类似的值时row = 1 and col = 104,它应该返回CZ,但它返回D@

row = 1
col = 104
div = col
column_label = str()
while div:
    (div, mod) = divmod(div, 26)
    column_label = chr(mod + 64) + column_label

print column_label

我在做什么有什么问题?

(此代码是 EXCEL 列的参考,我在其中提供了行、列 ID 值并期望 ALPHABETIC 值相同。)

4

8 回答 8

31

Note The code now shown in this answer isn't what it was when you accepted it because I've found and fixed a bug it had that prevented it from properly handling column numbers greater than 702 (corresponding to Excel column 'ZZ').

It's quite likely you never used the previous version with large enough column numbers to have encountered the issue. FWIW, the Microsoft Excel specifications and limits say it supports worksheets with up to 1,048,576 rows by 16,384 columns (i.e. column 'XFD').

LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

def excel_style(row, col):
    """ Convert given row and column number to an Excel-style cell name. """
    result = []
    while col:
        col, rem = divmod(col-1, 26)
        result[:0] = LETTERS[rem]
    return ''.join(result) + str(row)

if __name__ == '__main__':
    addresses = [(1,  1), (1, 26),
                 (1, 27), (1, 52),
                 (1, 53), (1, 78),
                 (1, 79), (1, 104),
                 (1, 18253), (1, 18278),
                 (1, 702),  # -> 'ZZ1'
                 (1, 703),  # -> 'AAA1'
                 (1, 16384), # -> 'XFD1'
                 (1, 35277039)]

    print('({:3}, {:>10}) --> {}'.format('row', 'col', 'Excel'))
    print('==========================')
    for row, col in addresses:
        print('({:3}, {:10,}) --> {!r}'.format(row, col, excel_style(row, col)))

Output:

(row,       col) --> Excel
========================
(  1,         1) --> 'A1'
(  1,        26) --> 'Z1'
(  1,        27) --> 'AA1'
(  1,        52) --> 'AZ1'
(  1,        53) --> 'BA1'
(  1,        78) --> 'BZ1'
(  1,        79) --> 'CA1'
(  1,       104) --> 'CZ1'
(  1,     18253) --> 'ZZA1'
(  1,     18278) --> 'ZZZ1'
(  1,       702) --> 'ZZ1'
(  1,       703) --> 'AAA1'
(  1,     16384) --> 'XFD1'
(  1,  35277039) --> 'BYEBYE1'
于 2013-10-03T21:02:39.893 回答
17

您有几个索引问题:

因此,要解决您的问题,您需要使所有索引匹配:

def colToExcel(col): # col is 1 based
    excelCol = str()
    div = col 
    while div:
        (div, mod) = divmod(div-1, 26) # will return (x, 0 .. 25)
        excelCol = chr(mod + 65) + excelCol

    return excelCol

print colToExcel(1) # => A
print colToExcel(26) # => Z
print colToExcel(27) # => AA
print colToExcel(104) # => CZ
print colToExcel(26**3+26**2+26) # => ZZZ
于 2013-10-03T08:43:32.147 回答
9

我喜欢 maritineau 的回答,因为它的代码看起来简单易懂。但它无法处理大于 26**2 + 26 的列号。所以我修改了它的一部分。

def excel_col(col):
    """Covert 1-relative column number to excel-style column label."""
    quot, rem = divmod(col-1,26)
    return excel_col(quot) + chr(rem+ord('A')) if col!=0 else ''



if __name__=='__main__':
    for i in [1, 26, 27, 26**3+26**2+26]:
        print 'excel_col({0}) -> {1}'.format(i, excel_col(i))

结果

excel_col(1) -> A
excel_col(26) -> Z
excel_col(27) -> AA
excel_col(18278) -> ZZZ
于 2014-07-21T09:41:09.570 回答
6
def ColNum2ColName(n):
   convertString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   base = 26
   i = n - 1

   if i < base:
      return convertString[i]
   else:
      return ColNum2ColName(i//base) + convertString[i%base]

编辑:对,对 zondo。

我只是A, B, .. AA, AB, ...用数字作为数字基数A-Z

A = 1
B = 2
 .
 .
X = 24
Y = 25
Z = 26
 .
 .
 .

这是一种没有任何 while 循环等的简单方法,适用于任何数字> 0

于 2016-05-20T09:16:28.810 回答
2

我认为它是这样的:

def get_col(col):
    """Get excel-style column names"""
    (div, mod) = divmod(col, 26)
    if div == 0:
        return str(unichr(mod+64))
    elif mod == 0:
        return str(unichr(div+64-1)+'Z')
    else:
        return str(unichr(div+64)+unichr(mod+64))

一些测试:

>>> def get_col(col):
...     (div, mod) = divmod(col, 26)
...     if div == 0:
...         return str(unichr(mod+64))
...     elif mod == 0:
...         return str(unichr(div+64-1)+'Z')
...     else:
...         return str(unichr(div+64)+unichr(mod+64))
... 
>>> get_col(105)
'DA'
>>> get_col(104)
'CZ'
>>> get_col(1)
'A'
>>> get_col(55)
'BC'
于 2013-10-03T08:37:52.590 回答
1

我想我想通了。 divmod(104,26) 给出 mod=0 使得 chr(0+64) = 64 即'@'。

如果我在 column_label 之前添加这一行,"mod=26 if mod==0 else mod" 我认为它应该可以正常工作

column_label=''
div=104
while div:
    (div, mod) = divmod(div, 26)
    mod=26 if mod==0 else mod
    column_label = chr(mod + 64) + column_label

print column_label
于 2013-10-03T08:31:05.230 回答
0

使用此代码:

def xlscol(colnum):
    a = []
    while colnum:
        colnum, remainder = divmod(colnum - 1, 26)
        a.append(remainder)
    a.reverse()
    return ''.join([chr(n + ord('A')) for n in a])
于 2016-03-11T17:09:22.870 回答
0

这是另一种在没有循环的情况下使用 pandas 多索引数据框获取 excel 列名的方法。这是对广义基对基转换器的修改,因此代码比其他一些选项要长一些,但我认为它是有效的:

def xlcolumn(num):
    base = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
    baseln = len(base)
    idx = [""]+base
    num = num-1

    # create pandas multiindex using idx, base
    # current excel version has 16384 columns (A --> XFD), so multiindex needs to have a minimum of 3 levels:
    #   (26x26x26 = 17576 > 16384 columns) 

    index = pd.MultiIndex.from_product([idx, idx, idx],names=['level 1', 'level 2', 'level 3'])
    df = pd.DataFrame(index = index)
    df = df.drop("",level = 'level 3')
    df = df.iloc[:baseln].append(df.drop("",level = 'level 2'))
    df['val']=1

    if num < baseln:
        xlcol = str(df.iloc[num].name[2])
    elif num >= baseln and num < baseln**2:
        xlcol = str(df.iloc[num].name[1])+str(df.iloc[num].name[2])
    else:
        xlcol = str(df.iloc[num].name[0])+str(df.iloc[num].name[1])+str(df.iloc[num].name[2])

    return xlcol

于 2019-07-22T19:11:37.993 回答