复制单元格样式openpyxl

42

我正在尝试将工作簿中的一个名为default_sheet的表复制到一个新表new_sheet中。

我已经成功创建了一个新表,并从默认表格复制了值。如何将每个单元格的样式也复制到新表格的单元格中呢?

new_sheet = workbook.create_sheet()
new_sheet.title = sheetName
default_sheet = workbook.get_sheet_by_name('default')
new_sheet = workbook.get_sheet_by_name(sheetName)
for row in default_sheet.rows:
    col_idx = float(default_sheet.get_highest_column())
starting_col = chr(65 + int(col_idx))
for row in default_sheet.rows:
    for cell in row:
        new_sheet[cell.get_coordinate()] = cell.value
        <copy also style of each cell>
我目前正在使用openpyxl 1.8.2,但我打算切换到1.8.5。 一种解决方案是使用复制:
from copy import copy, deepcopy

new_sheet._styles[cell.get_coordinate()] = copy(
        default_sheet._styles[cell.get_coordinate()])

我找到了一种复制的方法,但我不确定它是否是最好的方法,而且它不能复制单元格的宽度/高度! - FotisK
1
是的,你需要使用复制。每个工作表都保留了一个单元格样式字典,可以进行复制。但实际上,你最好尝试使用1.9分支,它有更清晰的界面来处理这种情况。 - Charlie Clark
4个回答

56

截至 openpyxl 2.5.4,Python 3.4 版本:(与以下旧版本相比略有细微变化)

new_sheet = workbook.create_sheet(sheetName)
default_sheet = workbook['default']

from copy import copy

for row in default_sheet.rows:
    for cell in row:
        new_cell = new_sheet.cell(row=cell.row, column=cell.col_idx,
                value= cell.value)
        if cell.has_style:
            new_cell.font = copy(cell.font)
            new_cell.border = copy(cell.border)
            new_cell.fill = copy(cell.fill)
            new_cell.number_format = copy(cell.number_format)
            new_cell.protection = copy(cell.protection)
            new_cell.alignment = copy(cell.alignment)

对于 openpyxl 2.1 版本

new_sheet = workbook.create_sheet(sheetName)
default_sheet = workbook['default']

for row in default_sheet.rows:
    for cell in row:
        new_cell = new_sheet.cell(row=cell.row_idx,
                   col=cell.col_idx, value= cell.value)
        if cell.has_style:
            new_cell.font = cell.font
            new_cell.border = cell.border
            new_cell.fill = cell.fill
            new_cell.number_format = cell.number_format
            new_cell.protection = cell.protection
            new_cell.alignment = cell.alignment

8
我将使用openpyxl 2.4.1进行翻译。cell.font或者cell.border是一个StyleProxy的实例,如果保存工作簿时使用这种类型,会引发异常。你必须将其复制到新单元格中,如下所示:new_cell.font = copy(cell.font) - dawncold
1
谢谢dawncold,我一直在想为什么会出现“不可哈希类型”错误。 - otocan
2
值得注意的是,工作簿现在已经有了一个copy_worksheet方法,可以为您复制样式。 - Charlie Clark
1
这对于合并单元格无效,并且单元格的尺寸也不会保留。 - wbzy00
1
这不是精确复制,当我尝试时有些混乱,未对齐正确。 - greendino
显示剩余4条评论

27

StyleableObject 实现将样式存储在单个列表 _style 中,单元格的样式属性实际上是对此数组的 getter 和 setter。您可以为每个样式实现单独的复制,但这样会很慢,特别是如果您在繁忙的内部循环中执行此操作。

如果您愿意深入私有类属性,那么有一种更快的克隆样式的方法:

if cell.has_style:
    new_cell._style = copy(cell._style)

这是优化后的WorksheetCopy类在_copy_cells方法中实现它的方式,供参考。


1
如果您希望在多个单元格中使用相同的样式,那么“命名样式”会更有意义。 - Charlie Clark
2
很好的代码。正是我现在需要的。但是实际上,在某些情况下,“命名样式”可能是更好的方法。 - Jean-Francois T.
感谢您提供的简洁回答。 - Vineesh TP
1
这个对我不起作用,使用的是 openpyxl 3.0.9。 - netotz
在3.x分支中,openpyxl存储单元格样式的方式没有改变,任何错误都来自于您的代码。 - ldrg

3
也许这是最方便的方式。
    from openpyxl import load_workbook
    from openpyxl import Workbook
    read_from = load_workbook('path/to/file.xlsx')
    read_sheet = read_from.active
    write_to = Workbook()
    write_sheet = write_to.active
    write_sheet['A1'] = read_sheet['A1'].value
    write_sheet['A1'].style = read_sheet['A1'].style
    write_to.save('save/to/file.xlsx')

2
这并不是所有的样式,这个答案更好,但必须使用copy - dawncold

1
我整理了以上的答案,下面的代码对我有效。 (它可以复制单元格的值和格式)
from openpyxl import load_workbook
from copy import copy

wb = load_workbook(filename = 'unmerge_test.xlsx') #your file name
ws = wb['sheet_merged'] #your sheet name in the file above

for group in list(ws.merged_cells.ranges):
    min_col, min_row, max_col, max_row = group.bounds
    cell_start = ws.cell(row = min_row, column = min_col)
    top_left_cell_value = cell_start.value

    ws.unmerge_cells(str(group))

    for i_row in range(min_row, max_row + 1):
        for j_col in range(min_col, max_col + 1): 
            ws.cell(row = i_row, column = j_col, value = top_left_cell_value)
            #copy the cell format
            ws.cell(row = i_row, column = j_col).alignment = copy(cell_start.alignment)
            ws.cell(row = i_row, column = j_col).border = copy(cell_start.border)
            ws.cell(row = i_row, column = j_col).font = copy(cell_start.font)

wb.save("openpyxl_unmerged.xlsx")

希望这能帮到您!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接