Python 自动化 Excel 合并 / 拆分单元格


Python 自动化 Excel 合并 / 拆分单元格

Python 自动化 Excel 合并 / 拆分单元格详细教程

在制作报表、台账、汇总表的时候,合并单元格是很常用的功能,能让表格结构更清晰美观。Python可以轻松实现单元格的合并与拆分,批量处理效率远超手动操作。本文将详细介绍各种合并/拆分场景的实现方法,包含完整代码示例和最佳实践。


一、环境准备

1.1 安装依赖库

bash
pip install openpyxl pandas

1.2 注意事项

合并/拆分单元格前请备份文件:

1. 合并单元格后会导致部分单元格数据丢失,合并前确保数据已经正确整理

2. 拆分单元格后需要补充数据,避免出现空值

3. 包含合并单元格的表格在排序、筛选、计算时会出现问题,建议数据处理完成后再合并

4. 合并单元格不要过度使用,会增加后续数据处理的难度


二、合并单元格基础操作

2.1 合并指定范围的单元格

python
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, PatternFill, Border, Side

wb = Workbook()
ws = wb.active

# 合并A1到F1单元格作为大标题
ws.merge_cells("A1:F1")
# 给合并后的单元格赋值(赋值给合并区域的左上角单元格即可)
ws["A1"] = "2026年第一季度销售报表"
# 设置样式
title_font = Font(name="微软雅黑", size=16, bold=True)
title_alignment = Alignment(horizontal="center", vertical="center")
ws["A1"].font = title_font
ws["A1"].alignment = title_alignment
# 设置行高
ws.row_dimensions[1].height = 30

# 合并表头:A2到B2为"基本信息",C2到F2为"销售数据"
ws.merge_cells("A2:B2")
ws["A2"] = "基本信息"
ws.merge_cells("C2:F2")
ws["C2"] = "销售数据"

# 表头样式
header_font = Font(bold=True, color="FFFFFF")
header_fill = PatternFill(start_color="3498db", end_color="3498db", fill_type="solid")
header_alignment = Alignment(horizontal="center", vertical="center")

for cell in ["A2", "C2"]:
    ws[cell].font = header_font
    ws[cell].fill = header_fill
    ws[cell].alignment = header_alignment

# 写入子表头
sub_headers = ["日期", "区域", "产品A", "产品B", "产品C", "合计"]
for col, header in enumerate(sub_headers, 1):
    cell = ws.cell(row=3, column=col, value=header)
    cell.font = header_font
    cell.fill = header_fill
    cell.alignment = header_alignment

# 写入测试数据
data = [
    ["2026-01", "华东", 12000, 8500, 9800, "=SUM(C4:E4)"],
    ["2026-02", "华南", 15000, 9200, 10500, "=SUM(C5:E5)"],
    ["2026-03", "华北", 13500, 7800, 11200, "=SUM(C6:E6)"]
]

for row_idx, row_data in enumerate(data, 4):
    for col_idx, value in enumerate(row_data, 1):
        ws.cell(row=row_idx, column=col_idx, value=value)

# 调整列宽
for col in ["A", "B", "C", "D", "E", "F"]:
    ws.column_dimensions[col].width = 15

# 保存文件
wb.save("合并单元格示例.xlsx")
print("✅ 合并单元格完成!")

2.2 按行号列号合并

除了用Excel坐标,还可以用行号列号合并:

python
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# 合并第1行,第1列到第6列(等价于A1:F1)
ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=6)
ws["A1"] = "销售报表"

# 合并第2-4行,第1列(等价于A2:A4)
ws.merge_cells(start_row=2, start_column=1, end_row=4, end_column=1)
ws["A2"] = "第一季度"

wb.save("按坐标合并.xlsx")

2.3 合并多个不连续的单元格

python
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# 要合并的多个单元格范围
merge_ranges = [
    "A1:C1",  # 大标题
    "A2:A4",  # 区域列
    "D2:F2",  # 数据标题
    "A5:C5",  # 合计行标题
]

for range_str in merge_ranges:
    ws.merge_cells(range_str)

# 赋值
ws["A1"] = "销售数据汇总"
ws["A2"] = "华东区"
ws["D2"] = "销售明细"
ws["A5"] = "合计"

wb.save("多区域合并.xlsx")
print("✅ 多个区域合并完成!")

三、常见合并场景实战

3.1 相同内容自动合并

把相同内容的相邻单元格自动合并,比如相同区域、相同月份的行:

python
from openpyxl import load_workbook

wb = load_workbook("销售数据.xlsx")
ws = wb.active

# 按区域列(B列)合并相同区域的单元格
# 先找出相同内容的连续行
start_row = 2  # 从第二行开始(跳过表头)
current_value = ws.cell(row=start_row, column=2).value

for row in range(3, ws.max_row + 1):
    value = ws.cell(row=row, column=2).value
    if value != current_value:
        # 和上一个值不同,合并前面的连续行
        if start_row < row - 1:
            ws.merge_cells(start_row=start_row, start_column=2, end_row=row-1, end_column=2)
            print(f"✅ 合并B{start_row}:B{row-1},内容:{current_value}")
        start_row = row
        current_value = value

# 合并最后一组
if start_row < ws.max_row:
    ws.merge_cells(start_row=start_row, start_column=2, end_row=ws.max_row, end_column=2)
    print(f"✅ 合并B{start_row}:B{ws.max_row},内容:{current_value}")

wb.save("销售数据_合并相同区域.xlsx")

3.2 制作台账表头合并

制作复杂的多级表头,非常适合报表:

python
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, PatternFill

wb = Workbook()
ws = wb.active

# 第一级表头(合并整个第一行)
ws.merge_cells("A1:I1")
ws["A1"] = "XX公司员工信息台账"
ws["A1"].font = Font(size=18, bold=True)
ws["A1"].alignment = Alignment(horizontal="center", vertical="center")
ws.row_dimensions[1].height = 35

# 第二级表头
ws.merge_cells("A2:B2")
ws["A2"] = "基本信息"
ws.merge_cells("C2:E2")
ws["C2"] = "工作信息"
ws.merge_cells("F2:H2")
ws["F2"] = "薪资信息"
ws.merge_cells("I2:I3")
ws["I2"] = "备注"

# 第三级表头
headers = [
    "姓名", "部门", "入职日期", "岗位", "职级",
    "基本工资", "绩效工资", "补贴"
]
for col, header in enumerate(headers, 1):
    cell = ws.cell(row=3, column=col, value=header)
    cell.alignment = Alignment(horizontal="center", vertical="center")

# 表头样式
header_fill = PatternFill(start_color="3498db", end_color="3498db", fill_type="solid")
white_font = Font(color="FFFFFF", bold=True)
for row in [2, 3]:
    for col in range(1, 10):
        cell = ws.cell(row=row, column=col)
        cell.fill = header_fill
        cell.font = white_font

# 调整列宽
for col in ["A", "B", "C", "D", "E", "F", "G", "H", "I"]:
    ws.column_dimensions[col].width = 15

wb.save("员工台账表头.xlsx")
print("✅ 台账多级表头合并完成!")

3.3 合并居中所有表头

批量处理多个工作表的表头合并居中:

python
from openpyxl import load_workbook
from openpyxl.styles import Alignment

wb = load_workbook("多工作表报表.xlsx")

center_alignment = Alignment(horizontal="center", vertical="center")

for ws in wb.worksheets:
    # 合并第一行作为标题
    if ws.max_column > 1:
        ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=ws.max_column)
        ws.cell(row=1, column=1).alignment = center_alignment
        print(f"✅ 已合并工作表{ws.title}的表头")

wb.save("多工作表报表_表头合并.xlsx")

四、拆分单元格

4.1 拆分指定合并单元格

python
from openpyxl import load_workbook

wb = load_workbook("合并单元格示例.xlsx")
ws = wb.active

# 查看所有合并单元格
print("当前合并单元格:")
for merged_range in ws.merged_cells.ranges:
    print(f"  - {merged_range}")

# 拆分指定单元格范围
ws.unmerge_cells("A1:F1")
print("✅ 已拆分A1:F1")

# 拆分所有合并单元格
for merged_range in list(ws.merged_cells.ranges):
    ws.unmerge_cells(str(merged_range))
    print(f"✅ 已拆分{merged_range}")

wb.save("拆分单元格示例.xlsx")

4.2 拆分后自动填充数据

拆分单元格后,原来只有左上角单元格有数据,其他单元格为空,可以自动填充:

python
from openpyxl import load_workbook

wb = load_workbook("销售数据_合并相同区域.xlsx")
ws = wb.active

# 先获取所有合并单元格信息
merged_info = []
for merged_range in ws.merged_cells.ranges:
    # 获取合并范围和值
    min_row, min_col, max_row, max_col = merged_range.bounds
    value = ws.cell(row=min_row, column=min_col).value
    merged_info.append((min_row, min_col, max_row, max_col, value))

# 拆分所有合并单元格
for merged_range in list(ws.merged_cells.ranges):
    ws.unmerge_cells(str(merged_range))

# 填充拆分后的空单元格
for min_row, min_col, max_row, max_col, value in merged_info:
    for row in range(min_row, max_row + 1):
        for col in range(min_col, max_col + 1):
            ws.cell(row=row, column=col, value=value)
    print(f"✅ 已拆分并填充{min_row},{min_col}到{max_row},{max_col},值:{value}")

wb.save("拆分后填充数据.xlsx")
print("✅ 拆分并填充完成!")

4.3 批量拆分所有Excel文件中的合并单元格

python
import os
from openpyxl import load_workbook

folder_path = "报表文件/"

for filename in os.listdir(folder_path):
    if filename.endswith(".xlsx") and not filename.startswith("~$"):
        file_path = os.path.join(folder_path, filename)
        print(f"正在处理:{filename}")
        
        wb = load_workbook(file_path)
        for ws in wb.worksheets:
            # 获取所有合并单元格信息
            merged_info = []
            for merged_range in ws.merged_cells.ranges:
                min_row, min_col, max_row, max_col = merged_range.bounds
                value = ws.cell(row=min_row, column=min_col).value
                merged_info.append((min_row, min_col, max_row, max_col, value))
            
            # 拆分
            for merged_range in list(ws.merged_cells.ranges):
                ws.unmerge_cells(str(merged_range))
            
            # 填充
            for min_row, min_col, max_row, max_col, value in merged_info:
                for row in range(min_row, max_row + 1):
                    for col in range(min_col, max_col + 1):
                        ws.cell(row=row, column=col, value=value)
        
        new_filename = f"拆分_{filename}"
        wb.save(os.path.join(folder_path, new_filename))
        print(f"✅ 处理完成,保存为:{new_filename}")

print("✅ 批量拆分完成!")

五、合并/拆分高级技巧

5.1 合并单元格后保留所有数据

默认合并单元格只会保留左上角的数据,如果需要合并后显示所有数据,可以先把内容合并:

python
from openpyxl import load_workbook

wb = load_workbook("待合并文件.xlsx")
ws = wb.active

# 合并A2:A5单元格,把所有内容用换行符连接
content = []
for row in range(2, 6):
    value = ws.cell(row=row, column=1).value
    if value:
        content.append(str(value))

merged_content = "\n".join(content)

# 合并单元格
ws.merge_cells("A2:A5")
ws["A2"] = merged_content
# 设置自动换行
ws["A2"].alignment = Alignment(wrap_text=True, vertical="center")
# 调整行高
ws.row_dimensions[2].height = len(content) * 15

wb.save("合并并保留内容.xlsx")
print("✅ 合并完成,已保留所有内容")

5.2 按条件动态合并

根据数据内容动态决定是否合并:

python
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# 示例数据
data = [
    ["日期", "区域", "销售额"],
    ["2026-01-01", "华东", 12000],
    ["2026-01-01", "华东", 8500],
    ["2026-01-01", "华南", 9800],
    ["2026-01-02", "华东", 15000],
    ["2026-01-02", "华北", 11000],
]

# 写入数据
for row in data:
    ws.append(row)

# 按日期列合并相同日期的单元格
start_row = 2
current_date = ws["A2"].value

for row in range(3, ws.max_row + 1):
    date = ws[f"A{row}"].value
    if date != current_date:
        if start_row < row - 1:
            ws.merge_cells(f"A{start_row}:A{row-1}")
            print(f"✅ 合并日期{current_date}的单元格")
        start_row = row
        current_date = date

# 合并最后一组
if start_row < ws.max_row:
    ws.merge_cells(f"A{start_row}:A{ws.max_row}")
    print(f"✅ 合并日期{current_date}的单元格")

# 设置居中
for merged_range in ws.merged_cells.ranges:
    min_row, min_col, _, _ = merged_range.bounds
    ws.cell(row=min_row, column=min_col).alignment = Alignment(horizontal="center", vertical="center")

wb.save("按日期合并.xlsx")

5.3 合并跨列居中(不合并单元格)

有时候我们只是想要内容跨列居中显示,并不想真的合并单元格(避免影响后续数据处理),可以使用对齐方式实现:

python
from openpyxl import Workbook
from openpyxl.styles import Alignment

wb = Workbook()
ws = wb.active

# 不合并单元格,实现跨列居中效果
ws["A1"] = "跨列居中显示,不合并单元格"
# 设置跨列居中对齐
ws["A1"].alignment = Alignment(horizontal="centerContinuous", vertical="center")
# 设置A1到F1都使用这个对齐
for col in range(1, 7):
    ws.cell(row=1, column=col).alignment = Alignment(horizontal="centerContinuous", vertical="center")

wb.save("跨列居中示例.xlsx")
print("✅ 跨列居中设置完成,没有合并单元格")

5.4 合并单元格后添加边框

合并单元格后边框可能会不完整,需要单独设置:

python
from openpyxl import Workbook
from openpyxl.styles import Border, Side

wb = Workbook()
ws = wb.active

# 合并单元格
ws.merge_cells("A1:C3")
ws["A1"] = "带边框的合并单元格"

# 设置边框
thin_border = Border(
    left=Side(style='thin'),
    right=Side(style='thin'),
    top=Side(style='thin'),
    bottom=Side(style='thin')
)

# 给合并区域的所有单元格设置边框
for row in range(1, 4):
    for col in range(1, 4):
        ws.cell(row=row, column=col).border = thin_border

wb.save("合并单元格加边框.xlsx")

六、使用pandas处理合并单元格

pandas默认会自动展开合并单元格,非常适合数据处理:

6.1 读取带合并单元格的Excel

python
import pandas as pd

# 读取带合并单元格的Excel,pandas会自动填充拆分后的单元格
df = pd.read_excel("合并单元格示例.xlsx", header=[0, 1])  # 多级表头
print("读取到的数据:")
print(df)

# 处理后保存,就没有合并单元格了
df.to_excel("拆分后的数据.xlsx", index=False)
print("✅ 已保存为无合并单元格的文件")

6.2 导出时设置合并单元格

pandas本身不支持合并单元格,但可以和openpyxl配合实现:

python
import pandas as pd
from openpyxl import load_workbook

# 准备数据
df = pd.DataFrame({
    "日期": ["2026-01", "2026-01", "2026-02", "2026-02"],
    "区域": ["华东", "华南", "华东", "华北"],
    "销售额": [12000, 8500, 15000, 9800]
})

# 先保存为普通Excel
df.to_excel("pandas合并示例.xlsx", index=False)

# 用openpyxl打开合并单元格
wb = load_workbook("pandas合并示例.xlsx")
ws = wb.active

# 合并相同日期的单元格
ws.merge_cells("A2:A3")
ws.merge_cells("A4:A5")

# 设置居中
from openpyxl.styles import Alignment
ws["A2"].alignment = Alignment(horizontal="center", vertical="center")
ws["A4"].alignment = Alignment(horizontal="center", vertical="center")

wb.save("pandas合并示例.xlsx")
print("✅ pandas导出并合并单元格完成")

七、常见问题与解决方案

7.1 合并单元格后数据丢失

问题:合并单元格后,其他单元格的数据不见了

原因:Excel合并单元格只会保留左上角的内容,其他单元格内容会被丢弃

解决方案

合并前先把需要保留的内容合并到左上角单元格,参考5.1节方法
重要数据合并前一定要备份

7.2 合并单元格后排序/筛选异常

问题:带合并单元格的表格排序、筛选时数据错乱

原因:合并单元格会导致行高列宽不一致,排序筛选时无法正确对应

解决方案

数据处理阶段不要合并单元格,所有处理完成后再合并
必须合并的话,先拆分所有合并单元格,处理完成后再重新合并

7.3 拆分单元格后有空值

问题:拆分后只有第一个单元格有数据,其他都是空的

解决方案

拆分前先记录所有合并单元格的位置和值,拆分后自动填充所有单元格,参考4.2节方法

7.4 合并单元格的高度/宽度不对

问题:合并后的单元格内容显示不全

解决方案

手动设置行高列宽:
python
# 设置行高
ws.row_dimensions[1].height = 30
# 设置列宽
ws.column_dimensions["A"].width = 20
# 开启自动换行
from openpyxl.styles import Alignment
ws["A1"].alignment = Alignment(wrap_text=True)

7.5 批量合并速度慢

问题:上万行数据按条件合并时速度很慢

解决方案

先把数据读出来在内存中处理,记录需要合并的区间,最后一次性合并,不要边遍历边合并
不需要保留格式的话,先处理好数据再写入Excel,比修改已有文件快很多

八、最佳实践

1. 数据处理与展示分离:数据处理阶段不要合并单元格,最后生成报表展示时再合并

2. 合并前备份:重要文件合并前先备份,避免数据丢失

3. 合并后验证:合并完成后检查内容是否正确,边框是否完整

4. 避免过度合并:不要为了美观过度合并单元格,会大幅增加后续维护难度

5. 批量处理先记录:批量合并/拆分前,先把所有需要处理的位置记录下来,再统一操作

6. 拆分必填充:拆分单元格后一定要填充所有空值,避免后续处理时出现空数据

7. 优先用跨列居中:只是需要居中效果的话,优先用centerContinuous对齐,不要真的合并单元格

合并单元格是把双刃剑,合理使用可以让表格更美观,滥用会给数据处理带来很多麻烦。建议在数据计算、分析、筛选阶段保持原始格式,最终输出报表时再根据需要合并。

© 版权声明

相关文章

暂无评论

none
暂无评论...