码迷,mamicode.com
首页 > 其他好文 > 详细

解决xlsxwriter的format覆盖问题

时间:2018-08-08 21:28:22      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:nbsp   excel   覆盖   文件   拷贝   转换   fast   完成   bsp   

 最近在用Python写一个生成Excel日历的脚本, 功能上实现没多大问题, 倒是在xlsxwriter的格式写入上遇到了一个大坑.

 举个例子:

import xlsxwriter

wb = xlsxwriter.Workbook("test.xlsx")
ws = wb.add_worksheet()

# 加粗和字体样式
bold = wb.add_format({"bold":True})
fontsize = wb.add_format({"font_size":15})

ws.write("A1", "test", bold)
ws.write("A2", "test", fontsize)

 可以预见A1格是粗体, A2格字体则大了几号. 但我们无法同时给一个单元格套用两种样式, 或者说, 单元格只接受最后套用的样式:

ws.write("A1", "test", bold)
ws.write("A1", "test", fontsize)

 这一格的文字只会变大而不会变粗 .

 另一个问题是, 无法分别给一个单元格写入值和样式. 对于单个单元格, 必须在写入值的同时为单元格写入样式. 关于这个, 可以用 set_column 和 set_row 解决, 它们的实质是设置该列/行的默认样式:

ws.set_column("A:A", None, bold)
ws.set_row(2, None, fontsize) # 第三行
ws.write("A1", "test1")
ws.write("A2", "test2", fontsize)
ws.write("A3", "test3")

 运行代码可以发现A1继承了A列的默认样式(加粗), 而A2只有字体变大了, 样式覆盖问题依然存在; 另外, A3只继承了行默认样式: 不管 set_column 和 set_row 的先后顺序如何, 行默认样式会覆盖列默认样式. 

 对于规模极小的表格, 可以分别为单元格设置单独而完全的格式, 但我们依旧希望能够分别/分次为单元格追加新样式, 例如先对一些单元格设置字体, 然后再对一些单元格设置背景色, 最后再给整体添加框线等.

 Xlsxwriter被设计为只能写入xlsx文件而不能读取或修改, 但问题在于, 我们xlsxwriter写入的数据会暂存在内存中, 直到最后close()时才会写入到文件中, 那么理应能够从缓存中修改, 最起码读出某单元格的值和样式. 而官方目前没有这样的设计, 所以我们可以先将设置的样式缓存下来, 如果某单元格已经有了样式那就合并, 最后再调用xlsxwriter的方法写入到表格中.

 由于样式和值需要同时写入到单元格中, 所以值的写入也需要缓存. 我为我的Excel日历生成脚本写的缓存机制代码如下:

cells_format = {}
cells_value = {}


def write_format(row, col, append_format: dict):
    cell = xlsxwriter.worksheet.xl_rowcol_to_cell_fast(row, col) # 将行列号转换成A1这样的格式
    fmt = cells_format[cell].copy() if cell in cells_format else {}
    fmt.update(append_format)
    cells_format[cell] = fmt

# 批量套用样式
def write_formats(s_row, s_col, e_row, e_col, append_format: dict):
    for row in range(s_row, e_row + 1):
        for col in range(s_col, e_col + 1):
            write_format(row, col, append_format)


def write_value(row, col, value):
    cell = xlsxwriter.worksheet.xl_rowcol_to_cell_fast(row, col)
    cells_value[cell] = value


def write_finish(wb: xlsxwriter.Workbook,
                 ws: xlsxwriter.Workbook.worksheet_class):
    values, formats = set(cells_value.keys()), set(cells_format.keys())
    for c in values.difference(formats):
        ws.write(c, cells_value[c])
    for c in values.intersection(formats):
        ws.write(c, cells_value[c], wb.add_format(cells_format[c]))
    for c in formats.difference(values):
        ws.write_blank(c, None, wb.add_format(cells_format[c]))

 首先通过write_value和write_format(s)将值和样式写入缓存字典中, 如果已存在样式, 就拷贝并追加新样式, 在最后调用write_finish完成写入. 有兴趣的读者可以将它模块化, 再整合进一些其他功能, 方便xlsxwriter的写入.

 然后就可以欢快地写样式了, 最后是一个简单的小日历:

# 每周前5天颜色较深
write_formats(0, 0, 4, 4, {"bg_color":"#C8C8C8"}) write_formats(0, 5, 4, 6, {"bg_color":"#D9D9D9"}) # 外框线
write_formats(0, 0,
4, 0, {"left":1}) write_formats(0, 6, 4, 6, {"right":1}) write_formats(0, 0, 0, 6, {"top":1}) write_formats(4, 0, 4, 6, {"bottom":1}) for i in range(1, 32): write_value(i//7, i%7, i) wb = xlsxwriter.Workbook("test.xlsx") ws = wb.add_worksheet() write_finish(wb, ws) wb.close()

效果如下:

技术分享图片

解决xlsxwriter的format覆盖问题

标签:nbsp   excel   覆盖   文件   拷贝   转换   fast   完成   bsp   

原文地址:https://www.cnblogs.com/zaevi/p/xlsxwriter-format-overwrite.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!