如何检测Excel工作表中的合并单元格?

21

我尝试从一个包含合并单元格的Excel表中读取数据。使用openpyxl读取合并单元格时,第一个合并单元格包含值,其余单元格为空。

我想知道每个单元格是否已合并以及合并了多少个单元格,但我找不到任何能够实现此功能的函数。该表还有其他空单元格,因此我无法使用这些信息。


未来读者注意:在只读模式下,不要使用load_workbook(..., read_only=True),因为合并单元格的信息在只读模式下不可用。 - undefined
5个回答

30

您可以在工作表上使用merged_cells.rangesmerged_cell_ranges已经被弃用,从版本2.5.0-b1(2017-10-19)开始变更为merged_cells.ranges),如下所示:(在某一行中似乎找不到)

from openpyxl import load_workbook
wb = load_workbook(filename='a file name')
sheet_ranges = wb['Sheet1']

print(sheet_ranges.merged_cells.ranges)

1
您提到的新的merged_cells方法似乎完全没有记录,除了您提供的快速弃用提及。我错了吗?(这里没有结果 - Atralb
有用的提示(至少我发现的):ranges 返回一个 MergeCell 对象列表。每个对象都有一个 bounds 属性,该属性返回合并单元格的 4 个角落的元组,格式为 (col_low, row_low, col_high, row_high) - Tomerikoo

10

要测试单个单元格是否合并,可以检查类型:

cell = sheet.cell(row=15, column=14)
if isinstance(cell, MergedCell):
  print("Oh no, the cell is merged!")
else:
  print("This cell is not merged.")

要“取消合并”所有单元格,您可以使用函数unmerge_cells
for items in sorted(sheet.merged_cell_ranges):
  print(items)
  sheet.unmerge_cells(str(items))

3
自本答案发布以来,openpyxl似乎已经发生了改变。这里的建议不再有效。 - Kade
据我所知,它应该适用于OpenPyXL 2.6.2版本,这是当前的版本。 - 0x4a6f4672
我可以确认,在2.6.2中它可以工作 - 我没有尝试过3.0.X,但在回答这个问题的时候,我相信2.6.2是最新的版本。 - Alex L
它在3.0.4上无法工作请参见 - Carson
这对我来说是可行的,最新版本(3.0.7)以及开发(r8820 / r8821),甚至3.0.4都可以。当然,merged_cell_ranges已被弃用,但它仍然有效。 - Ángel
1
这个解决方案是不正确的,问题根本不在于 openpyxl 版本。问题在于合并单元格的第一个单元格被确定为 Cell 而不是 MergedCell(因此第一个答案中明确指定 merged_cells.ranges 中为 MergedCell 的答案是正确的,而这个答案则不正确)。 - Oleg Radchenko

7

为了测试单元格是否合并,我遍历了sheet.merged_cells.ranges,就像@A. Lau建议的那样。不幸的是,像@0x4a6f4672展示的检查单元格类型的方法已经不再适用。

这里有一个函数可以帮助您解决这个问题。

def testMerge(row, column):
    cell = sheet.cell(row, column)
    for mergedCell in sheet.merged_cells.ranges:
        if (cell.coordinate in mergedCell):
            return True
    return False

5
该问题询问如何检测合并单元格并读取它们,但是目前提供的答案只涉及检测取消合并。这里有一个函数可以返回逻辑值,即用户将在合并单元格上看到的值:
import sys
from openpyxl import load_workbook
from openpyxl.cell.cell import MergedCell


def cell_value(sheet, coord):
  cell = sheet[coord]
  if not isinstance(cell, MergedCell):
    return cell.value

  # "Oh no, the cell is merged!"
  for range in sheet.merged_cells.ranges:
    if coord in range:
      return range.start_cell.value

  raise AssertionError('Merged cell is not in any merge range!')


workbook = load_workbook(sys.argv[1])
print(cell_value(workbook.active, sys.argv[2]))

1

这些都有帮助(谢谢),但当我在几个电子表格中使用这些方法时,它没有像我预期的那样取消合并所有单元格。我不得不循环和重新测试合并才最终让它们全部完成。在我的情况下,需要进行4次操作才能如预期地取消合并所有单元格:

    mergedRanges = sheet_ranges.merged_cells.ranges
    ### How many times do we run unmerge?
    i=0
    ### keep testing and removing ranges until they are all actually gone
    while mergedRanges:
        for entry in mergedRanges:
            i+=1
            print("  unMerging: " + str(i) + ": " +str(entry))
            ws.unmerge_cells(str(entry))

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