将excel或电子表格列字母转换为Pythonic方式的数字

时间:2011-08-31 18:51:42

标签: python excel google-sheets python-2.x

将excel样式列转换为数字(从1开始)有更多pythonic方法吗?

最多两个字母的工作代码:

def column_to_number(c):
    """Return number corresponding to excel-style column."""
    number=-25
    for l in c:
        if not l in string.ascii_letters:
            return False
        number+=ord(l.upper())-64+25
    return number

代码运行:

>>> column_to_number('2')
False
>>> column_to_number('A')
1
>>> column_to_number('AB')
28

三封信不起作用。

>>> column_to_number('ABA')
54
>>> column_to_number('AAB')
54

参考:question answered in C#

17 个答案:

答案 0 :(得分:23)

有一种方法可以使它更加pythonic(使用三个或更多字母并使用更少的幻数):

def col2num(col):
    num = 0
    for c in col:
        if c in string.ascii_letters:
            num = num * 26 + (ord(c.upper()) - ord('A')) + 1
    return num

作为使用reduce的单行代码(不检查输入并且不太可读,所以我不推荐它):

col2num = lambda col: reduce(lambda x, y: x*26 + y, [ord(c.upper()) - ord('A') + 1 for c in col])

答案 1 :(得分:5)

这是一种方法。它是XlsxWriter模块中代码的变体:

def col_to_num(col_str):
    """ Convert base26 column string to number. """
    expn = 0
    col_num = 0
    for char in reversed(col_str):
        col_num += (ord(char) - ord('A') + 1) * (26 ** expn)
        expn += 1

    return col_num


>>> col_to_num('A')
1
>>> col_to_num('AB')
28
>>> col_to_num('ABA')
729
>>> col_to_num('AAB')
704

答案 2 :(得分:3)

使用openpyxl

import openpyxl
(column_string, row) = openpyxl.cell.coordinate_from_string(address)
column = openpyxl.cell.column_index_from_string(column_string) 

答案 3 :(得分:3)

在Python 2.7.1和3.5.2

中测试的单行程序
excel_col_num = lambda a: 0 if a == '' else 1 + ord(a[-1]) - ord('A') + 26 * excel_col_num(a[:-1])

excel_col_name = lambda n: '' if n <= 0 else excel_col_name((n - 1) // 26) + chr((n - 1) % 26 + ord('A'))

多线同样

def excel_column_name(n):
    """Number to Excel-style column name, e.g., 1 = A, 26 = Z, 27 = AA, 703 = AAA."""
    name = ''
    while n > 0:
        n, r = divmod (n - 1, 26)
        name = chr(r + ord('A')) + name
    return name

def excel_column_number(name):
    """Excel-style column name to number, e.g., A = 1, Z = 26, AA = 27, AAA = 703."""
    n = 0
    for c in name:
        n = n * 26 + 1 + ord(c) - ord('A')
    return n

def test (name, number):
    for n in [0, 1, 2, 3, 24, 25, 26, 27, 702, 703, 704, 2708874, 1110829947]:
        a = name(n)
        n2 = number(a)
        a2 = name(n2)
        print ("%10d  %-9s  %s" % (n, a, "ok" if a == a2 and n == n2 else "error %d %s" % (n2, a2)))

test (excel_column_name, excel_column_number)
test (excel_col_name, excel_col_num)

所有测试打印

         0             ok
         1  A          ok
         2  B          ok
         3  C          ok
        24  X          ok
        25  Y          ok
        26  Z          ok
        27  AA         ok
       702  ZZ         ok
       703  AAA        ok
       704  AAB        ok
   2708874  EXCEL      ok
1110829947  COLUMNS    ok

答案 4 :(得分:2)

安装openpyxl模块后,您可以将以下内容添加到控制台:

import openpyxl
from openpyxl.utils import get_column_letter, column_index_from_string
workbook = openpyxl.load_workbook('your_workbook.xlsx')
sheet = wb.get_sheet_by_name('your_sheet_from_workbook')
print(get_column_letter(1))
print(column_index_from_string('A'))

只需更改字母和数字以满足您的需求,或创建一个for循环来完成整个项目的工作。我希望这有帮助。干杯。

答案 5 :(得分:1)

这是一个递归解决方案:

def column_string_to_num(s):
    n = ord(s[-1]) - 64
    if s[:-1]:
        return 26 * (column_string_to_num(s[:-1])) + n
    else:
        return n
    
column_string_to_num("AB")
#output: 28

也可以通过类似的方式递归定义逆:

def column_num_to_string(n):
    n, rem = divmod(n - 1, 26)
    next_char = chr(65 + rem)
    if n:
        return column_string(n) + next_char
    else:
        return next_char

column_num_to_string(28)
#output: 'AB'

答案 6 :(得分:1)

阅读完本文后,我决定找到一种直接在Excel单元格中进行操作的方法。它甚至可以解释Z之后的列。

只需将此公式粘贴到任意列的任何行的单元格中,它将为您提供相应的数字。

=IF(LEN(SUBSTITUTE(ADDRESS(ROW(),COLUMN(),4),ROW(),""))=2,
 CODE(LEFT(SUBSTITUTE(ADDRESS(ROW(),COLUMN(),4),ROW(),""),1))-64*26)+
 CODE(RIGHT(SUBSTITUTE(ADDRESS(ROW(),COLUMN(),4),ROW(),""),1)-64),
 CODE(SUBSTITUTE(ADDRESS(ROW(),COLUMN(),4),ROW(),""))-64)

这里的主题是获取列的字母,获取它的Code()并减去64,基于字母A的ASCII字符代码为64的事实。

答案 7 :(得分:1)

在VBA中,这应该是你要找的东西:

Function columnNumber(colLetter As String) As Integer

    Dim colNumber As Integer
    Dim i As Integer

    colLetter = UCase(colLetter)
    colNumber = 0
    For i = 1 To Len(colLetter)
        colNumber = colNumber + (Asc(Mid(colLetter, Len(colLetter) - i + 1, 1)) - 64) * 26 ^ (i - 1)
    Next

    columnNumber = colNumber

End Function

您可以像使用Excel公式一样使用它 - 以字母形式输入列,作为字符串(例如,“AA”),无论列长度如何都应该有效。

由于您进行计数的方式处理三个字母,您的代码会中断 - 您需要使用26。

答案 8 :(得分:1)

我做了这个单行:

colNameToNum = lambda cn: sum([((ord(cn[-1-pos]) - 64) * 26 ** pos) for pos in range(len(cn))])

它通过以相反的顺序迭代字母并乘以1,26,26 * 26等来工作,然后对列表求和。这种方法也可以与更长的字母串兼容。

我称之为:

print(colNameToNum(“AA”))#27

print(colNameToNum(“XFD”))#允许的最高列,我相信。结果= 16384

答案 9 :(得分:0)

对于从零开始的索引(例如A = 0,B = 1等):

null

答案 10 :(得分:0)

您还可以通过一系列乘法和加法来执行此操作,如下所示。此处的“ A”等于1。运行时间为O(n),其中n是列的长度col

import functools
def spreadsheet_column_encoding(col):
    return functools.reduce(
        lambda result, char: result * 26 + ord(char) - ord("A") + 1, col, 0
    )

例如ZZ = 702

0 * 26 + 90 - 65 + 1 = 26
26 * 26 + 90 - 65 + 1 = 702

P.S:ord('Z') = 90

要将数字转换为列字母,请参见我的答案here。您可以使用除法和模量计算来做相反的事情。

答案 11 :(得分:0)

使用:

LETTERS = list(string.ascii_uppercase)
def column_number(column_id):
    return sum([(LETTERS.index(j)+1)*(26**i) for i,j in enumerate(column_id[::-1])])

这种单线纸有几个部分,所以这里是解释:

column_id[::-1]:反转字符串,例如将'AZ'转换为'ZA',这是有充分理由的,我们将在稍后介绍。

enumerate():产生可迭代的,例如(0, 'Z'), (1, 'A')

有一些观察:

 A -> 1  = (26**0)*1              # ** is the exponential operator
 B -> 2  = (26**0)*2 
 Z -> 26 = (26**0)*26
AA -> 27 = (26**0)*1  + (26**1)*1
AB -> 28 = (26**0)*2  + (26**1)*1
AZ -> 52 = (26**0)*26 + (26**1)*1  # recall that we have (0, 'Z'), (1, 'A')

反转column_idenumerate()使我们可以将索引用作26的指数。其余的现在变得微不足道了。

LETTERS.index(j):为我们提供LETTERS中字母的索引

sum():获取数字列表并返回总数。

答案 12 :(得分:0)

这就是我用的(写这篇文章之前写了):

def col_to_index(col):
    return sum((ord(c) - 64) * 26**i for i, c in enumerate(reversed(col))) - 1

一些跑步:

>>> col_to_index('A')
1
>>> col_to_index('AB')
28
>>> col_to_index('ABCD')
19010

答案 13 :(得分:0)

你可以使用这个oneliner使用理解和字符串,这很容易使用:

sum([string.ascii_lowercase.index(c) + 26 ** i for i,c in enumerate(col_letters)])

答案 14 :(得分:0)

巧合而优雅 Ruby 版本:

def col_num(col_name)
    col_name.split(//).inject(0) { |n, c| n * 26 + c.upcase.ord - "A".ord + 1 }
end

答案 15 :(得分:0)

只是这样做:

print ws.Range("E2").Column

呼叫示例:

from win32com import client
xl = client.Dispatch("Excel.Application")
wb = xl.Workbooks.Open("c:/somePath/file.xls")
xl.Visible = 1
ws = wb.Sheets("sheet 1")
print ws.Range("E2").Column

结果:

>>5

答案 16 :(得分:0)

我不确定我是否理解正确,你想将引用的C#代码“翻译”为python吗?如果是这样,你就走在了正确的轨道上;只需修改它:

def column_to_number(c):
  """Return number corresponding to excel-style column."""
  sum = 0
  for l in c:
    if not l in string.ascii_letters:
      return False
    sum*=26
    sum+=ord(l.upper())-64
  return sum