Преобразовать букву столбца Excel или таблицы в его число в стиле Pythonic - PullRequest
9 голосов
/ 31 августа 2011

Есть ли более питонический способ преобразования столбцов в стиле Excel в числа (начиная с 1)?

Рабочий код до двух букв:

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

Ссылка: на вопрос дан ответ на C #

Ответы [ 14 ]

24 голосов
/ 28 сентября 2012

Существует способ сделать его более питоническим (работает с тремя или более буквами и использует меньше магических чисел):

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

И в качестве однострочного с использованием метода Reducer (не проверяет ввод именее читабелен, поэтому я не рекомендую его):

col2num = lambda col: reduce(lambda x, y: x*26 + y, [ord(c.upper()) - ord('A') + 1 for c in col])
5 голосов
/ 07 мая 2013

Вот один из способов сделать это. Это вариант кода в модуле 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
3 голосов
/ 02 декабря 2017

Вы можете просто добавить следующее в консоль после установки модуля 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, чтобы выполнить работу для всего проекта. Надеюсь, это поможет. Приветствия.

3 голосов
/ 25 июля 2017

Однострочные тесты протестированы в 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
3 голосов
/ 27 марта 2015

Использование openpyxl

import openpyxl
(column_string, row) = openpyxl.cell.coordinate_from_string(address)
column = openpyxl.cell.column_index_from_string(column_string) 
1 голос
/ 14 октября 2015

Я сделал этот однострочный:

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

1 голос
/ 23 августа 2013

Прочитав это, я решил найти способ сделать это прямо в ячейках 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, исходя из того факта, что код символа ASCII для буквы A равен 64.

1 голос
/ 31 августа 2011

Это должно сделать в 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.

0 голосов
/ 20 ноября 2018

Вот что я использую (писал до того, как нашел эту страницу):

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
0 голосов
/ 03 октября 2016

Вы можете использовать этот oneliner, используя понятные и понятные строки:

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