其他答案存在的问题
关于@Charlie Clark所选的答案和其他使用http://thequickblog.com/merge-unmerge-cells-openpyxl-in-python代码的答案,你可以更轻松地取消合并单元格,无需处理range_boundaries
和转换。
我在所选答案中也遇到了一些问题,其中一些合并单元格会取消合并,而另一些则不会,一些取消合并的单元格会填充所需的数据,而其他单元格则不会。
问题在于worksheet.merged_cells.ranges
是一个迭代器,这意味着它是惰性评估的,因此当调用worksheet.unmerge_cells()
时,对象worksheet.merged_cells
被改变,并且在再次迭代合并单元格范围时发生副作用。
更好的解决方案
在我的情况下,我想要取消合并单元格,同时复制边框、字体和对齐信息:
+-------+------+
+-------+------+ | Date | Time |
| Date | Time | +=======+======+
+=======+======+ | Aug 6 | 1:00 |
| | 1:00 | -> +-------+------+
| Aug 6 | 3:00 | | Aug 6 | 3:00 |
| | 6:00 | +-------+------+
+-------+------+ | Aug 6 | 6:00 |
+-------+------+
对于当前最新版本的openpyxl==3.0.9
,我发现以下内容最适合我:
from copy import copy
from openpyxl import load_workbook, Workbook
from openpyxl.cell import Cell
from openpyxl.worksheet.cell_range import CellRange
from openpyxl.worksheet.worksheet import Worksheet
def unmerge_and_fill_cells(worksheet: Worksheet) -> None:
"""
Unmerges all merged cells in the given ``worksheet`` and copies the content
and styling of the original cell to the newly unmerged cells.
:param worksheet: The Excel worksheet containing the merged cells.
"""
all_merged_cell_ranges: list[CellRange] = list(
worksheet.merged_cells.ranges
)
for merged_cell_range in all_merged_cell_ranges:
merged_cell: Cell = merged_cell_range.start_cell
worksheet.unmerge_cells(range_string=merged_cell_range.coord)
for row_index, col_index in merged_cell_range.cells:
cell: Cell = worksheet.cell(row=row_index, column=col_index)
cell.value = merged_cell.value
cell.alignment = copy(merged_cell.alignment)
cell.border = copy(merged_cell.border)
cell.font = copy(merged_cell.font)
if __name__ == "__main__":
workbook: Workbook = load_workbook(
filename="workbook_with_merged_cells.xlsx"
)
worksheet: Worksheet = workbook["My Sheet"]
unmerge_and_fill_cells(worksheet=worksheet)
workbook.save(filename="workbook_with_unmerged_cells.xlsx")
简洁的解决方案
这里是一个更短的版本,没有注释并且不复制样式:
from openpyxl.worksheet.worksheet import Worksheet
def unmerge_and_fill_cells(worksheet: Worksheet) -> None:
for merged_cell_range in list(worksheet.merged_cells.ranges):
worksheet.unmerge_cells(range_string=merged_cell_range.start_cell)
for row_col_indices in merged_cell_range.cells:
worksheet.cell(*row_col_indices).value = merged_cell.value
...在list(ws.merged_cell_ranges)
,这样所有的单元格都会解除合并,因为它遍历列表(否则会跳过一些单元格,因为合并单元格的范围在变化)。 - Marta