Python完美處理Excel合并單元格(拆分填充+自動合并)的示例詳解
一、前言:Excel合并單元格的痛點(diǎn)
在日常辦公、數(shù)據(jù)爬蟲、數(shù)據(jù)分析、報(bào)表自動化場景中,Excel合并單元格是最讓人頭疼的格式問題之一。
常見痛點(diǎn):
- 合并單元格拆分后數(shù)據(jù)丟失:openpyxl原生拆分單元格后,只有左上角單元格保留數(shù)值,其余單元格為空,導(dǎo)致數(shù)據(jù)斷層、無法用于篩選、匹配數(shù)據(jù)。
- 樣式錯(cuò)亂:拆分/合并后字體、顏色、邊框、對齊方式丟失,報(bào)表格式崩壞。
- 無法可逆操作:拆分后想重新規(guī)整合并,沒有通用自動化方案,只能手動操作。
- 批量處理困難:多區(qū)域、多行多列合并單元格,人工修改效率極低。
為此,我基于 openpyxl 封裝了一套無損、可逆、全覆蓋的Excel合并單元格工具:
- 拆分合并單元格:自動填充全部空缺單元格,保留完整樣式
- 智能合并單元格:按行/按列自動合并相同值、支持指定區(qū)域合并
- 全程保留:字體、填充色、邊框、對齊、數(shù)字格式
- 拆分+合并雙向聯(lián)動,完美閉環(huán)
二、功能核心優(yōu)勢
- 真·無損拆分:拆分后原合并區(qū)域所有單元格自動填充左上角原值,解決數(shù)據(jù)空白問題
- 全樣式復(fù)刻:逐單元格復(fù)制字體、背景填充、邊框、對齊、數(shù)字格式
- 三種合并模式:按列縱向合并、按行橫向合并、自定義區(qū)域合并
- 可逆閉環(huán)邏輯:拆分全填充 → 合并清冗余,和Excel原生邏輯一致
- 安全不毀源文件:支持覆蓋原文件/另存新文件雙模式
三、完整工具源碼(可直接運(yùn)行)
依賴安裝:
pip install openpyxl
完整工具代碼:
from openpyxl import load_workbook
from copy import copy
# ===================== 拆分合并單元格(全區(qū)域填充值+保留樣式) =====================
def unmerge_merged_cells_fill_all(file_path, sheet_name="Sheet1", output_path=None):
"""
拆分所有合并單元格,拆分后原合并區(qū)域全部填充原左上角值,完整保留樣式
:param file_path: 輸入Excel路徑
:param sheet_name: 工作表名稱
:param output_path: 輸出路徑,默認(rèn)覆蓋原文件
:return: 處理后文件路徑
"""
# 加載工作簿,保留原格式
wb = load_workbook(file_path)
ws = wb[sheet_name]
# 提前讀取所有合并區(qū)域(拆分后會丟失合并信息,必須前置讀取)
merged_ranges = list(ws.merged_cells.ranges)
if not merged_ranges:
print("未檢測到合并單元格,無需處理")
return file_path
# 遍歷所有合并區(qū)域逐一處理
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))
# 全區(qū)域填充值 + 復(fù)刻樣式
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
# 完整復(fù)刻樣式
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)} 個(gè)合并區(qū)域,文件保存至: {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):
"""
單列縱向合并:同一列連續(xù)相同值自動合并
"""
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
# 掃描連續(xù)相同值區(qū)塊
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))
# 執(zhí)行合并+樣式同步
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):
"""
單行橫向合并:同一行連續(xù)相同值自動合并
"""
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
# ===================== 自定義區(qū)域合并 =====================
def manual_merge_range(file_path, sheet_name="Sheet1", min_r=1, min_c=1, max_r=1, max_c=1, output_path=None):
"""手動指定行列區(qū)域合并單元格"""
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"? 區(qū)域合并完成!({min_r},{min_c})~({max_r},{max_c})")
return save_path
# ===================== 一鍵聯(lián)動:拆分填充 + 重新合并 =====================
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\最終規(guī)整表格.xlsx"
# 1. 先拆分所有合并單元格,填充空白、保留樣式
unmerge_merged_cells_fill_all(input_file, output_path=temp_file)
# 2. 按需重新合并(示例:對第1列縱向合并相同內(nèi)容)
merge_cells_by_column(temp_file, col=1, start_row=1, output_path=final_file)
# 其他用法可單獨(dú)調(diào)用
# 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() 會出現(xiàn)數(shù)據(jù)丟失,原因是:openpyxl 拆分后僅左上角單元格保留值。
本工具解決方案:
- 先批量讀取所有合并區(qū)域(必須拆分前讀取,否則丟失記錄)
- 記錄每塊區(qū)域左上角單元格的 值 + 全套樣式
- 執(zhí)行拆分操作
- 遍歷區(qū)域內(nèi)所有單元格,批量填充值、復(fù)刻樣式
最終實(shí)現(xiàn):拆分后數(shù)據(jù)完整、格式不變,可直接用于數(shù)據(jù)分析。
2. 合并單元格核心邏輯
模擬人工規(guī)整表格邏輯:
- 掃描行/列中連續(xù)相同的值,自動識別合并區(qū)塊
- 執(zhí)行合并后,僅保留左上角值,其余單元格置空(符合Excel原生合并規(guī)則)
- 同步復(fù)刻左上角樣式,保證表格美觀統(tǒng)一
五、常用調(diào)用示例
1. 僅拆分填充所有合并單元格
unmerge_merged_cells_fill_all("test.xlsx", output_path="拆分后.xlsx")2. 按列自動合并相同內(nèi)容
# 第2列,從第2行開始縱向合并 merge_cells_by_column("拆分后.xlsx", col=2, start_row=2)3. 按行自動合并相同內(nèi)容
# 第3行橫向合并 merge_cells_by_row("test.xlsx", row=3)4. 手動指定區(qū)域合并
# 2-5行,1-3列區(qū)域合并 manual_merge_range("test.xlsx", min_r=2, min_c=1, max_r=5, max_c=3)六、適用場景總結(jié)
- 數(shù)據(jù)清洗:解決合并單元格導(dǎo)致的pandas讀取數(shù)據(jù)錯(cuò)位、空值問題
- 報(bào)表自動化:自動規(guī)整Excel表格格式,替代人工合并拆分
- 批量處理文件:海量Excel文件統(tǒng)一標(biāo)準(zhǔn)化格式
- 數(shù)據(jù)可逆處理:拆分填充數(shù)據(jù) → 規(guī)整合并,實(shí)現(xiàn)表格標(biāo)準(zhǔn)化閉環(huán)
到此這篇關(guān)于Python完美處理Excel合并單元格(拆分填充+自動合并)的示例詳解的文章就介紹到這了,更多相關(guān)Python Excel單元格合并內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python實(shí)現(xiàn)拆分合并Excel單元格并自動填充原左上角數(shù)據(jù)
- Python實(shí)現(xiàn)凍結(jié)Excel文件中的行、列和單元格
- Python實(shí)現(xiàn)快速鎖定Excel單元格與行列
- Python代碼實(shí)現(xiàn)精確設(shè)置Excel單元格數(shù)字格式
- Python實(shí)現(xiàn)鎖定指定Excel單元格區(qū)域
- 使用Python合并與拆分Excel單元格的實(shí)用方法
- Python使用openpyxl從URL讀取Excel并獲取單元格樣式
- Python設(shè)置Excel單元格邊框樣式的完全指南
相關(guān)文章
Django?Rest?Framework實(shí)現(xiàn)身份認(rèn)證源碼詳解
這篇文章主要為大家介紹了Django?Rest?Framework實(shí)現(xiàn)身份認(rèn)證源碼詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
Python-Flask:動態(tài)創(chuàng)建表的示例詳解
今天小編就為大家分享一篇Python-Flask:動態(tài)創(chuàng)建表的示例詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11
pycharm+django創(chuàng)建一個(gè)搜索網(wǎng)頁實(shí)例代碼
這篇文章主要介紹了pycharm+django創(chuàng)建一個(gè)搜索網(wǎng)頁實(shí)例代碼,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
python實(shí)現(xiàn)簡單溫度轉(zhuǎn)換的方法
這篇文章主要介紹了python實(shí)現(xiàn)簡單溫度轉(zhuǎn)換的方法,涉及Python操作字符串的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03
圖文詳解感知機(jī)算法原理及Python實(shí)現(xiàn)
感知機(jī)是二類分類的線性分類模型,其輸入為實(shí)例的特征向量,輸出為實(shí)例的類別(取+1和-1二值)。本文將為大家詳細(xì)講講感知機(jī)算法的原理及實(shí)現(xiàn),需要的可以參考一下2022-08-08
python matplotlib 畫dataframe的時(shí)間序列圖實(shí)例
今天小編就為大家分享一篇python matplotlib 畫dataframe的時(shí)間序列圖實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11

