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

时间:2018-12-19 13:21:45

标签: python excel openpyxl

Openpyxl可以告诉我max_rowmax_col,这是Excel工作表的“使用范围”。但是,如果以前选择或更改过此范围,则该范围可以包含不包含任何内容的单元格。

我想知道具有内容的最后一列和最后一行。

Discussion for VBA, here.

例如,如果-在“ Used Range”中为空白,而_表示“ Used Range”之外为空白,我想选择标记为b的列和标记为{{ 1}},即使Openpyxl在计算cmax_row时,也会在行/列中加上破折号。

max_col

1 个答案:

答案 0 :(得分:1)

我发现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行中删除。

它首先打印max_row报告的max_columnopenpyxl,然后在工作表中调用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()