【问题标题】:openpyxl python3 -- formatting whole rows ellicits strange behavioropenpyxl python3——格式化整行会引发奇怪的行为
【发布时间】:2013-07-31 02:02:27
【问题描述】:

我正在使用数据透视表 XLSX 文件并编写脚本以将它们解析为每个选项卡的新文件。

由于 openpyxl 默认不支持数据透视表,我需要做一些工作来重新插入在复制过程中丢失的数据透视表“样式”。

为此,我将遍历每一行和每一列,在第 0 列中查找值 Total。一旦找到,该行应全部更改为 bold=True

相反,我收到不稳定的行为,有时会在第一个 None 之后将所有单元格加粗。我的print('bolding totals') 消息显示它正在正确评估每一行/单元格。也许我是不是脑子有问题,把循环上的缩进搞砸了?

from openpyxl import Workbook
from openpyxl import load_workbook
from copy import deepcopy

wb = load_workbook(filename=r'input.xlsx')

# Print 1
sheetlist = wb.get_sheet_names()
print(sheetlist)

for i in range(len(sheetlist)-1):
    dest_filename = r''+sheetlist[i]+'.xlsx'
    new_wb = Workbook()
    ws = wb.get_sheet_by_name(sheetlist[i])
    new_wb.add_sheet(ws, 0)

    for k in range(0, new_wb.worksheets[0].get_highest_row()):
        print(new_wb.worksheets[0].cell(row=k, column=0).value)
        # ignore empty cells
        if new_wb.worksheets[0].cell(row=k, column=0).value is not None:
            if 'Total' in new_wb.worksheets[0].cell(row=k, column=0).value:
                for j in range(0, new_wb.worksheets[0].get_highest_column()):
                    print('bolding totals, '+str(k), str(j))
                    new_wb.worksheets[0].cell(
                        row=k, column=j).style.font.bold = True
            elif 'Total' not in new_wb.worksheets[0].cell(row=k, column=0).value:
                for j in range(0, new_wb.worksheets[0].get_highest_column()):
                    print('not bolding anything')
                    new_wb.worksheets[0].cell(
                        row=k, column=j).style.font.bold = False

    # remove the blank sheet created in new_wb by openpyxl
    new_wb.remove_sheet(new_wb.get_sheet_by_name('Sheet'))
    print(new_wb.get_sheet_names())
    new_wb.save(dest_filename)
    break  # set to break after one sheet for testing

print('finished')

在这一点上,我怀疑这是 openpyxl 处理样式中的一个错误。我又进行了一次非常简单的编辑,但出现了奇怪的行为。

如果我们有一个带有粗体/非粗体单元格的简单布局。 然后我们运行这个简单的命令来改变一个单元格:

>>> new_wb.worksheets[0].cell(row=10,column=0).style.font.bold = False

整个列的输出都会发生变化,而不仅仅是单元格。

【问题讨论】:

  • 嗨,openpyxl 中的错误对我来说并不是很令人震惊。我以前遇到过问题。对我来说,通过 COM 端口驱动来重写整个应用程序以直接使用 Excel 比修复 openpyxl 更容易。这是我的帖子,有答案;希望对您有所帮助:stackoverflow.com/questions/18145313/…
  • 我投票结束这个问题,尽管它写得很好而且很有趣,因为:(a) 它没有答案,无论是否被接受; (b) 与实际产出和期望产出的联系已失效; (c) OP 已近两年未访问 SO; (d) 现在可能已经修复了任何相关的 openpyxl 错误; (e) 尽管它现在实际上无法回答,但它仍然显示为一个悬而未决的问题。
  • @AleksanderLidtke 我不记得有关于此的错误报告。您的评论似乎暗示 openpyxl 非常错误,我认为这不是一个公平的表示。当然,如果可以的话,直接使用 Excel 会很棒。您可能还想查看 xlwings 来执行此操作。

标签: python openpyxl


【解决方案1】:

在 openpyxl 2.0 之前,单元格样式在单元格之间共享:这是使用源 XML 中的指针实现的保留:两个(或更多)单元格都将使用样式“1”。为一个单元格更改此样式将意味着为所有单元格更改它,这听起来像是这里观察到的行为。

从那时起,虽然在实现上发生了各种变化,但在更改一个单元格的样式时不再有任何副作用。一个重要的变化是格式化对象,例如Font 是直接可用的,并且不必包装在样式中。

还有一些其他变化:工作表无法在工作簿之间复制,因为它们依赖于存储在父工作簿中的数据。

没有原始文件很难确定,但以下代码应该适用于 openpyxl >= 2.2

from openpyxl import Workbook
from openpyxl import load_workbook

wb = load_workbook(filename='input.xlsx', read_only=True)

for sheet in wb.sheetnames:

    dest_filename = '{0}.xlsx'.format(sheet)
    new_wb = Workbook()
    del new_wb["Sheet"]

    ws1 = wb[sheet]
    ws2 = new_wb.create_sheet(sheet)

    for row in ws1:
        ws2.append([c.value for c in row])
        first = row[0]
        if first.data_type == "s" and "Total" in first.value:
            for idx in range(len(row)):
                cell = ws2.cell(row=ws2.max_row, column=idx+1)
                bolded = cell.font.copy(bold=True)
                cell.font = bolded

    new_wb.save(dest_filename)
    print("saving {0}".format(dest_filename))

print('finished')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    • 2020-03-24
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-04
    相关资源
    最近更新 更多