如何在Openpyxl中查找最后一个非空单元格?

4
Openpyxl可以告诉我Excel表格的“已使用范围”中的max_rowmax_col,但是该范围可能包括没有内容的单元格,如果它们曾经被选择或更改过。我想知道最后一列和最后一行的内容。例如,如果-代表“已使用范围”中的空白单元格,_表示“已使用范围”之外的空白单元格,则我想要选择标有bc的列和行,即使Openpyxl在计算max_rowmax_col时会包括带有破折号的行/列。(这里是有关VBA讨论的链接)。
aaaaa---__
aaaaa-b-__
aaaaa---__
--------__
--c-----__
--------__
__________
__________

1
可能是Openpyxl max_row and max_column wrongly reports a larger figure的重复问题。 - Charlie Clark
1个回答

9

我发现 openpyxl 可以正确地报告已保存文件的 max_row 和 max_col 的值,但如果你在保存之前要操作工作表的内容并且需要这些值,则仍然存在问题。

没有内置的方法来处理此问题,所以最好的选择是自己搜索行和列,最好从报告的值开始限制搜索范围,并向上和向左搜索。

工作表对象允许你逐个访问行,但只能通过 .itercols() 访问单个列。是否比在一个循环中扫描所有列更快,将取决于你预期工作表有多少空白。

from openpyxl import load_workbook
wb = load_workbook('test.xlsx')
wb.worksheets[0]['h6'] = None

print((wb.worksheets[0].max_row, wb.worksheets[0].max_column))

def find_edges(sheet):
    row = sheet.max_row
    while row > 0:
        cells = sheet[row]
        if all([cell.value is None for cell in cells]):
            row -= 1
        else:
            break
    if row == 0:
        return 0, 0

    column = sheet.max_column
    while column > 0:
        cells = next(sheet.iter_cols(min_col=column, max_col=column, max_row=row))
        if all([cell.value is None for cell in cells]):
            column -= 1
        else:
            break
    return row, column

print(find_edges(wb.worksheets[0]))

在这个例子中,我加载了一个Excel表格,其中包含您建议的数据,还有一个仍在H6中的值,在第3行被删除。
它首先打印由openpyxl报告的max_rowmax_column,然后使用该表格调用find_edges,以找到所需的实际值。
对于非常少数据的大型表格,您可能希望尝试通过简单地迭代所有列(一旦确定了最后一行(以限制大小))来替换列扫描,以加快速度,如下所示:
columns = sheet.iter_cols(max_row=row)
column = 1
ci = 1
while True:
    try:
        cells = next(columns)
        if not all([cell.value is None for cell in cells]):
            column = ci
        ci += 1
    except StopIteration:
        break

但我预计第一种方式对于大多数有用的用例来说是最快的。

如果您更喜欢简短而不是易读:

def find_edges2(sheet):
    def row():
        for r in range(sheet.max_row, 0, -1):
            if not all([cell.value is None for cell in sheet[r]]):
               return r

    row = row()
    if not row:
        return 0, 0

    def column():
        for c in range(sheet.max_column, 0, -1):
            if not all([cell.value is None for cell in next(sheet.iter_cols(min_col=c, max_col=c, max_row=row))]):
                return c

    return row, column()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接