web-dev-qa-db-fra.com

obtenir les numéros de ligne et de colonne à partir de la valeur de coordonnées dans openpyxl

J'essaie de convertir une valeur de coordonnées dans Excel en un numéro de ligne et un numéro de colonne dans openpyxl.

Par exemple, si ma coordonnée de cellule est D4, je veux trouver les numéros de ligne et de colonne correspondants à utiliser pour les opérations futures, dans le cas ligne = 3, colonne = 3. Je peux facilement obtenir le numéro de ligne en utilisant ws.cell('D4').row qui retourne 4 alors il suffit de soustraire 1. Mais un argument similaire ws.cell('D4').column retourne D et je ne sais pas comment le mettre facilement sous forme int pour opérations ultérieures. Je me tourne donc vers vous, les sages de stackoverflow. Pouvez-vous m'aider?

32
A Alstone

Ce que vous voulez, c'est openpyxl.utils.coordinate_from_string() et openpyxl.utils.column_index_from_string()

from openpyxl.utils.cell import coordinate_from_string, column_index_from_string
xy = coordinate_from_string('A4') # returns ('A',4)
col = column_index_from_string(xy[0]) # returns 1
row = xy[1]
48
Adam Morris

openpyxl a une fonction appelée get_column_letter qui convertit un nombre en lettre de colonne.

from openpyxl.utils import get_column_letter
print(get_column_letter(1))

1 -> A

50 -> AXE

1234-- AUL

Je l'utilise comme:

from openpyxl import Workbook
from openpyxl.utils import get_column_letter

#create Excel type item
wb = Workbook()
# select the active worksheet
ws = wb.active

counter = 0
for column in range(1,6):
    column_letter = get_column_letter(column)
    for row in range(1,11):
        counter = counter +1
        ws[column_letter + str(row)] = counter

wb.save("sample.xlsx")

enter image description here

40
Ohm

Cela se fonde sur la réponse de Nathan. Fondamentalement, sa réponse ne fonctionne pas correctement lorsque la ligne et/ou la colonne ont plus d'un caractère de large. Désolé - je suis allé un peu trop loin. Voici le script complet:

def main():
    from sys import argv, stderr

    cells = None

    if len(argv) == 1:
        cells = ['Ab102', 'C10', 'AFHE3920']
    else:
        cells = argv[1:]

    from re import match as rematch

    for cell in cells:
        cell = cell.lower()

        # generate matched object via regex (groups grouped by parentheses)
        m = rematch('([a-z]+)([0-9]+)', cell)

        if m is None:
            from sys import stderr
            print('Invalid cell: {}'.format(cell), file=stderr)
        else:
            row = 0
            for ch in m.group(1):
                # ord('a') == 97, so ord(ch) - 96 == 1
                row += ord(ch) - 96
            col = int(m.group(2))

            print('Cell: [{},{}] '.format(row, col))

if __name__ == '__main__':
    main()

Tl; dr avec un tas de commentaires ...

# make cells with multiple characters in length for row/column
# feel free to change these values
cells = ['Ab102', 'C10', 'AFHE3920']

# import regex
from re import match as rematch

# run through all the cells we made
for cell in cells:
    # make sure the cells are lower-case ... just easier
    cell = cell.lower()

    # generate matched object via regex (groups grouped by parentheses)
    ############################################################################
    # [a-z] matches a character that is a lower-case letter
    # [0-9] matches a character that is a number
    # The + means there must be at least one and repeats for the character it matches
    # the parentheses group the objects (useful with .group())
    m = rematch('([a-z]+)([0-9]+)', cell)

    # if m is None, then there was no match
    if m is None:
        # let's tell the user that there was no match because it was an invalid cell
        from sys import stderr
        print('Invalid cell: {}'.format(cell), file=stderr)
    else:
        # we have a valid cell!
        # let's grab the row and column from it

        row = 0

        # run through all of the characters in m.group(1) (the letter part)
        for ch in m.group(1):
            # ord('a') == 97, so ord(ch) - 96 == 1
            row += ord(ch) - 96
        col = int(m.group(2))

        # phew! that was a lot of work for one cell ;)
        print('Cell: [{},{}] '.format(row, col))

print('I hope that helps :) ... of course, you could have just used Adam\'s answer,\
but that isn\'t as fun, now is it? ;)')
3
dylnmc

Ancien sujet, mais la réponse n'est pas correcte!

dylnmc la méthode était bonne, mais contient quelques erreurs. La ligne calculée pour les coordonnées de cellule comme "AA1" ou "AAB1" n'est pas correcte.

Voici la version corrigée en fonction.

NOTE: Cette fonction retourne la vraie coordonnée. Si vous souhaitez l'utiliser par exemple dans ExcelWriter, ROW et COL doivent être déduits d'un. Remplacez donc la dernière ligne par return (row-1, col-1)

Par exemple, "AA1" est [1,27] et "AAA1" est [1,703]; mais le python doit les avoir comme [0,26] et [0,702].

import re

def coord2num(coord):
    cell = coord.lower()

    # generate matched object via regex (groups grouped by parentheses)
    m = re.match('([a-z]+)([0-9]+)', cell)

    if m is None:
        print('Invalid cell: {}'.format(cell))
        return [None,None]
    else:
        col = 0
        for i,ch in enumerate(m.group(1)[::-1]):
            n = ord(ch)-96
            col+=(26**i)*(n)

        row = int(m.group(2))

    return[row,col]
0
Mehdi