python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python Excel单元格合并

Python完美处理Excel合并单元格(拆分填充+自动合并)的示例详解

作者:幸福清风

还在为Excel合并单元格拆分后数据丢失、样式错乱而烦恼吗,本文分享一套基于openpyxl的无损拆分与智能合并工具,自动填充空缺数据并完整保留字体、边框等样式,实现可逆闭环,彻底解决数据断层问题,让你的表格处理更高效

一、前言:Excel合并单元格的痛点

在日常办公、数据爬虫、数据分析、报表自动化场景中,Excel合并单元格是最让人头疼的格式问题之一。

常见痛点:

为此,我基于 openpyxl 封装了一套无损、可逆、全覆盖的Excel合并单元格工具:

二、功能核心优势

三、完整工具源码(可直接运行)

依赖安装:

pip install openpyxl

完整工具代码:

from openpyxl import load_workbook
from copy import copy


# ===================== 拆分合并单元格(全区域填充值+保留样式) =====================
def unmerge_merged_cells_fill_all(file_path, sheet_name="Sheet1", output_path=None):
    """
    拆分所有合并单元格,拆分后原合并区域全部填充原左上角值,完整保留样式
    :param file_path: 输入Excel路径
    :param sheet_name: 工作表名称
    :param output_path: 输出路径,默认覆盖原文件
    :return: 处理后文件路径
    """
    # 加载工作簿,保留原格式
    wb = load_workbook(file_path)
    ws = wb[sheet_name]

    # 提前读取所有合并区域(拆分后会丢失合并信息,必须前置读取)
    merged_ranges = list(ws.merged_cells.ranges)
    if not merged_ranges:
        print("未检测到合并单元格,无需处理")
        return file_path

    # 遍历所有合并区域逐一处理
    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

    # 保存文件
    output_path = output_path if output_path else file_path
    wb.save(output_path)
    print(f"✅ 拆分完成!共处理 {len(merged_ranges)} 个合并区域,文件保存至: {output_path}")
    return output_path


# ===================== 按列纵向自动合并相同值 =====================
def merge_cells_by_column(file_path, sheet_name="Sheet1", start_row=1, end_row=None, col=None, output_path=None):
    """
    单列纵向合并:同一列连续相同值自动合并
    """
    wb = load_workbook(file_path)
    ws = wb[sheet_name]
    max_row = ws.max_row if end_row is None else end_row

    merge_blocks = []
    current_start = start_row
    prev_val = ws.cell(row=start_row, column=col).value

    # 扫描连续相同值区块
    for r in range(start_row + 1, max_row + 1):
        curr_val = ws.cell(row=r, column=col).value
        if curr_val != prev_val:
            if current_start != r - 1:
                merge_blocks.append((current_start, col, r - 1, col))
            current_start = r
            prev_val = curr_val
    # 收尾最后一段
    if current_start != max_row:
        merge_blocks.append((current_start, col, max_row, col))

    # 执行合并+样式同步
    for min_r, min_c, max_r, max_c in merge_blocks:
        ws.merge_cells(min_row=min_r, min_col=min_c, max_row=max_r, max_col=max_c)
        top_cell = ws.cell(min_r, min_c)
        for r in range(min_r, max_r + 1):
            for c in range(min_c, max_c + 1):
                if not (r == min_r and c == min_c):
                    cell = ws.cell(r, c)
                    cell.value = None
                    cell.font = copy(top_cell.font)
                    cell.fill = copy(top_cell.fill)
                    cell.border = copy(top_cell.border)
                    cell.alignment = copy(top_cell.alignment)
                    cell.number_format = top_cell.number_format

    save_path = output_path if output_path else file_path
    wb.save(save_path)
    print(f"✅ 列合并完成,共 {len(merge_blocks)} 处合并,保存至:{save_path}")
    return save_path


# ===================== 按行横向自动合并相同值 =====================
def merge_cells_by_row(file_path, sheet_name="Sheet1", start_col=1, end_col=None, row=None, output_path=None):
    """
    单行横向合并:同一行连续相同值自动合并
    """
    wb = load_workbook(file_path)
    ws = wb[sheet_name]
    max_col = ws.max_column if end_col is None else end_col

    merge_blocks = []
    current_start = start_col
    prev_val = ws.cell(row=row, column=start_col).value

    for c in range(start_col + 1, max_col + 1):
        curr_val = ws.cell(row=row, column=c).value
        if curr_val != prev_val:
            if current_start != c - 1:
                merge_blocks.append((row, current_start, row, c - 1))
            current_start = c
            prev_val = curr_val
    if current_start != max_col:
        merge_blocks.append((row, current_start, row, max_col))

    for min_r, min_c, max_r, max_c in merge_blocks:
        ws.merge_cells(min_row=min_r, min_col=min_c, max_row=max_r, max_col=max_c)
        top_cell = ws.cell(min_r, min_c)
        for r in range(min_r, max_r + 1):
            for c in range(min_c, max_c + 1):
                if not (r == min_r and c == min_c):
                    cell = ws.cell(r, c)
                    cell.value = None
                    cell.font = copy(top_cell.font)
                    cell.fill = copy(top_cell.fill)
                    cell.border = copy(top_cell.border)
                    cell.alignment = copy(top_cell.alignment)
                    cell.number_format = top_cell.number_format

    save_path = output_path if output_path else file_path
    wb.save(save_path)
    print(f"✅ 行合并完成,共 {len(merge_blocks)} 处合并,保存至:{save_path}")
    return save_path


# ===================== 自定义区域合并 =====================
def manual_merge_range(file_path, sheet_name="Sheet1", min_r=1, min_c=1, max_r=1, max_c=1, output_path=None):
    """手动指定行列区域合并单元格"""
    wb = load_workbook(file_path)
    ws = wb[sheet_name]
    ws.merge_cells(min_row=min_r, min_col=min_c, max_row=max_r, max_col=max_c)
    top_cell = ws.cell(min_r, min_c)

    for r in range(min_r, max_r + 1):
        for c in range(min_c, max_c + 1):
            if not (r == min_r and c == min_c):
                cell = ws.cell(r, c)
                cell.value = None
                cell.font = copy(top_cell.font)
                cell.fill = copy(top_cell.fill)
                cell.border = copy(top_cell.border)
                cell.alignment = copy(top_cell.alignment)
                cell.number_format = top_cell.number_format

    save_path = output_path if output_path else file_path
    wb.save(save_path)
    print(f"✅ 区域合并完成!({min_r},{min_c})~({max_r},{max_c})")
    return save_path


# ===================== 一键联动:拆分填充 + 重新合并 =====================
if __name__ == "__main__":
    # 配置文件路径
    input_file = r"C:\Users\Administrator\Desktop\cs11.xlsx"
    temp_file = r"C:\Users\Administrator\Desktop\temp_拆分后.xlsx"
    final_file = r"C:\Users\Administrator\Desktop\最终规整表格.xlsx"

    # 1. 先拆分所有合并单元格,填充空白、保留样式
    unmerge_merged_cells_fill_all(input_file, output_path=temp_file)

    # 2. 按需重新合并(示例:对第1列纵向合并相同内容)
    merge_cells_by_column(temp_file, col=1, start_row=1, output_path=final_file)

    # 其他用法可单独调用
    # merge_cells_by_row(input_file, row=2)
    # manual_merge_range(input_file, min_r=2, min_c=1, max_r=5, max_c=3)

四、核心逻辑解析

1. 拆分单元格核心逻辑

很多人直接使用 ws.unmerge_cells() 会出现数据丢失,原因是:openpyxl 拆分后仅左上角单元格保留值

本工具解决方案:

最终实现:拆分后数据完整、格式不变,可直接用于数据分析

2. 合并单元格核心逻辑

模拟人工规整表格逻辑:

五、常用调用示例

1. 仅拆分填充所有合并单元格

unmerge_merged_cells_fill_all("test.xlsx", output_path="拆分后.xlsx")

2. 按列自动合并相同内容

# 第2列,从第2行开始纵向合并 merge_cells_by_column("拆分后.xlsx", col=2, start_row=2)

3. 按行自动合并相同内容

# 第3行横向合并 merge_cells_by_row("test.xlsx", row=3)

4. 手动指定区域合并

# 2-5行,1-3列区域合并 manual_merge_range("test.xlsx", min_r=2, min_c=1, max_r=5, max_c=3)

六、适用场景总结

到此这篇关于Python完美处理Excel合并单元格(拆分填充+自动合并)的示例详解的文章就介绍到这了,更多相关Python Excel单元格合并内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文