日常处理Excel报表时,合并单元格往往导致数据导出后仅左上角有值,其余单元格为空,严重影响后续统计、匹配和数据库导入。手动拆分单元格并逐一填充不仅效率低,还容易破坏原有样式。本文介绍一个基于openpyxl的Python脚本,能自动读取所有合并区域,拆分后统一填充原左上角数值,并同步复制字体、边框、填充色、对齐等样式,无需二次手动调整。
一、环境依赖
本脚本仅依赖openpyxl库,用于读写.xlsx格式的Excel文件。安装命令如下:
二、完整可运行代码
- from openpyxl import load_workbook
- from copy import copy
- def unmerge_merged_cells_fill_all(file_path, sheet_name="Sheet1", output_path=None):
- """
- Excel拆分合并单元格,拆分后原合并区域的所有单元格全部填充原左上角的值
- :param file_path: str 输入Excel文件完整路径
- :param sheet_name: str 目标工作表名称,默认Sheet1
- :param output_path: str 输出文件路径,不传则直接覆盖原文件
- :return: str 处理完成后的文件路径
- """
- # 1. 加载工作簿,保留表格原有全部格式样式
- wb = load_workbook(file_path)
- ws = wb[sheet_name]
- # 2. 提前读取所有合并单元格区域(关键:拆分后无法获取合并范围,必须先缓存)
- merged_ranges = list(ws.merged_cells.ranges)
- if not merged_ranges:
- print("当前工作表未检测到任何合并单元格,无需执行处理")
- return
- # 3. 循环处理每一块合并区域
- for m_range in merged_ranges:
- # 获取合并区域边界:起始行、结束行、起始列、结束列
- min_row = m_range.min_row
- max_row = m_range.max_row
- min_col = m_range.min_col
- max_col = m_range.max_col
- # 获取合并区域左上角单元格与原始数值
- top_left_cell = ws.cell(row=min_row, column=min_col)
- top_left_value = top_left_cell.value
- # 拆分当前合并单元格
- ws.unmerge_cells(range_string=str(m_range))
- # 遍历原合并区域内所有单元格,统一填充左上角值并复制样式
- for row in range(min_row, max_row + 1):
- for col in range(min_col, max_col + 1):
- current_cell = ws.cell(row=row, column=col)
- # 填充数值
- current_cell.value = top_left_value
- # 复制左上角单元格全套样式,保证表格美观不混乱
- current_cell.font = copy(top_left_cell.font)
- current_cell.fill = copy(top_left_cell.fill)
- current_cell.border = copy(top_left_cell.border)
- current_cell.alignment = copy(top_left_cell.alignment)
- current_cell.number_format = top_left_cell.number_format
- # 4. 文件保存逻辑
- if output_path is None:
- output_path = file_path
- wb.save(output_path)
- print(f"处理完成!共拆分 {len(merged_ranges)} 个合并单元格区域,文件保存路径:{output_path}")
- return output_path
- if __name__ == "__main__":
- # Windows本地文件路径,r字符串避免转义符报错
- input_file = r"C:\Users\Administrator\Desktop\cs11.xlsx"
- # 方式1:直接覆盖原文件
- unmerge_merged_cells_fill_all(input_file)
- # 方式2:生成新文件,不修改原文件(取消注释使用)
- # new_file = r"C:\Users\Administrator\Desktop\cs11_处理后.xlsx"
- # unmerge_merged_cells_fill_all(input_file, output_path=new_file)
复制代码
三、核心逻辑解析
1. 预读所有合并区域
openpyxl在执行unmerge_cells后,工作表的合并记录会被移除,因此必须先通过ws.merged_cells.ranges将全部合并区域缓存到列表中。这一步是保证循环能够正确遍历所有区域的基石。
2. 获取左上角数据与样式
每个合并区域仅左上角单元格存有原始值,其余均为None。脚本在拆分前读取该单元格的value及font、fill、border、alignment、number_format等样式对象,作为后续填充的模板。
3. 拆分与批量填充
调用ws.unmerge_cells释放合并后,使用双重for循环遍历原区域所有单元格,统一写入先前缓存的左上角值,并通过copy()复制全套样式。
4. 样式同步的细节
使用copy()而非直接赋值,避免多个单元格引用同一个样式对象导致后续修改相互影响。支持的样式属性包括字体、填充、边框、对齐和数字格式,覆盖了日常报表所需的所有视觉要素。
四、两种使用方式
方式1:覆盖原文件
不指定output_path参数,处理后的结果直接写入原文件,适合不想产生额外文件的场景。
- input_file = r"C:\Users\Administrator\Desktop\cs11.xlsx"
- unmerge_merged_cells_fill_all(input_file)
复制代码
方式2:输出新文件,保留原始数据
通过output_path指定新路径,原文件不受影响,适合需要备份原始报表或对比处理前后结果的场景。
- input_file = r"C:\Users\Administrator\Desktop\cs11.xlsx"
- output_file = r"C:\Users\Administrator\Desktop\cs11_拆分填充后.xlsx"
- unmerge_merged_cells_fill_all(input_file, output_path=output_file)
复制代码
五、适用场景与扩展思路
适用场景:
- 生产月度汇总表、年度统计报表(常有多行多列合并);
- 财务台账、项目台账导出后的数据清洗;
- 数据导入数据库前的预处理,消除空白单元格以避免空值干扰;
- 配合pandas读取Excel前的规整步骤,确保数据完整。
扩展改造思路:
- 结合pandas向右填充:拆分后,可按年月分区对右侧连续空白进行填充;
- 批量处理文件夹:配合os模块遍历所有.xlsx文件;
- 过滤指定工作表:增加跳过逻辑,仅处理名称匹配的Sheet;
- 输出处理日志:记录每个文件拆分的合并区域数量,方便回溯。
六、常见问题
1. 路径报错:Windows路径中的反斜杠需要转义,建议在字符串前加r,如r"C:\...";或使用正斜杠。
2. 文件被占用:Excel打开时会锁定文件,运行脚本前请关闭相关Excel文件。
3. 不支持.xls:openpyxl仅支持.xlsx格式,旧版.xls文件需先用Excel另存为.xlsx。
4. 无合并单元格:脚本会自动检测并直接返回,不会生成空文件或报错。
总结:本脚本通过openpyxl实现了合并单元格的自动化拆分与数据样式填充,几十行代码即可替代大量手动操作,适用于各类Excel报表的日常处理。代码封装完整、注释清晰,可直接复制使用,也易于根据实际需求二次扩展。 |