一、问题的来源以及网上的错误方法

最近遇到了一个问题,给定了一个Excel模板,修改表格里面的内容,但是不能修改Excel表格的格式。用pywin32太慢,用xlrd只能读,用xlwt只能写。

很快,我查到了网上“修改Excel内容但保留格式”的方法,大概是需要用到另一个辅助的库xlutils,并为formatting_info参数配置为True,代码大概是这样的:

import xlrd
import xlwt
from xlutils.copy import copyrb = xlrd.open_workbook('open.xls', formatting_info=True)
wb = copy(rb)sheet = wb.get_sheet(0)
for r in range(8):for c in range(5):sheet.write(r, c, 'R%sC%s'%(r+1, c+1))wb.save('save.xls')

大部分格式的确是保住了,但是“修改了”的部分的格式惨不忍睹,一看这就是默认格式嘛。

于是继续查找,发现xlwt.Worksheet(工作表)对象的write函数的用法参数说明为:

write(r, c, label='', style=<xlwt.Style.XFStyle object at 0x0186A530>)

网上找到的教程也有说明,只要配置xlwt库的XFStyle类,并为write函数的第4个参数赋值,就可以为新写入的单元格设置单元格格式了。代码类似于这样,这段代码实现了对RC位置的单元格设置了20号宋体、上下水平居中、四边边框

style = xlwt.XFStyle()
style.font.height = 400
style.font.name = '宋体'
style.alignment.horz = xlwt.Alignment.HORZ_CENTER
style.alignment.vert = xlwt.Alignment.VERT_CENTER
style.borders.left    = xlwt.Borders.THIN
style.borders.right   = xlwt.Borders.THIN
style.borders.top     = xlwt.Borders.THIN
style.borders.bottom  = xlwt.Borders.THINsheet.write(r, c, 'R%sC%s'%(r+1, c+1), style)

然而众所周知,xlwt库只能写不能读,相当于我在设置单元格的样式的,原表格的样式对我是“盲”的。虽然我可以“手动”地记下来所有单元格的格式,然后“抄”过去,但是这多蛋疼啊。

于是继续网上查找资料,全部都是答非所问的结果,要么告诉我“怎么复制原表格而保留样式”,要么告诉我“如何修改单元格同时配置格式”,但没有一个是回答“如何修改单元格而保留格式”的。

二、根据属性名猜可以用的函数

没办法,代码小白的我,只好继续猜,猜猜看那个函数能做到这样的配置。

首先我尝试为工作表对象sheet的sheet.write函数的第4个参数配置“默认”项,企图让它“write”单元格的时候“不修改”格式,比如False啊、0啊、None啊、-1啊,都试过了,全部报错。

那么尝试找xlrd读取的单元格的cell对象,看看里面有没有存储格式信息。但是cell对象中的属性不多,很快就爬干净了,没有存储格式这样如此“细致”的内容。

线索断了,我只好穷举用xlrd读取的工作簿rb的所有属性函数,突然发现了一个看起来很像记录格式的东西,rb.xf_list,其中是一个大列表,里面记录的全是“xlrd.formatting.XF”类型的对象,而字体格式的对象名字不是叫做“XFStyle”吗,这可是非常一致了。

这可是一个很大的突破,我猜想Excel中的单元格格式,不是分别记录到各个单元格的对象的属性中,而是将工作簿中出现的样式汇总,再通过另一个方法把各个单元格设定的格式的“索引编号”读出来,于是就做到了记录各个单元格的格式信息。

得到了线索就有了进展,我找到xlrd读取的工作表sheet对象有一个sheet.cell_xf_index(rowx, colx)函数,返回结果是一个数值,而且针对相同格式的单元格布局,这个结果在相同格式单元格中计算返回的索引编号很一致!那么结果肯定是这个了!

于是我急急忙忙把rb.xf_list[sheet.cell_xf_index(rowx, colx)]赋值到了sheet.write函数的style参数上,期待奇迹的发生。

三、瞎猫碰不到死耗子,那就硬着头皮爬源码

果不其然,事情的进展不会这么顺利,果然出现了报错。

我突然想起来了write函数的说明,style的默认参数设置是“style=<xlwt.Style.XFStyle object at 0x0186A530>”,而我赋值的是“xlrd.formatting.XF”对象,这都不是一个库的东西,怎么能直接用呢。

但是我坚定一个信念,既然通过xlutils.copy库的copy函数可以把格式“复制”过去,那么肯定在某个时候发生了读取和写入,这个格式读写的“管道”肯定是通的,关键是我要找到它。

于是我撑住头皮,开始爬xlutils库的代码,xlutils.copy库的内容很干净,代码只有这些:

from xlutils.filter import process,XLRDReader,XLWTWriterdef copy(wb):w = XLWTWriter()process(XLRDReader(wb,'unknown.xls'),w)return w.output[0][1]

于是转头去爬这里引用了的xlutils.filter库。既然知道了rb.xf_list存储了xlrd格式的“单元格样式”,那么就找找看它什么时候转化为了xlwt格式的“单元格样式”。

按照关键词搜索,果然找了一系列的判断和转换,代码段大概是这样的:

for rdxf in rdbook.xf_list:wtxf = xlwt.Style.XFStyle()... 各种判断和转换self.style_list.append(wtxf)

那么很显然,我要找的就是self.style_list了。

那么按理说,我只要获取到“self.style_list”的“self”,也就是它的父对象“BaseWriter”的实例,就能获取到这个属性了(也只有这个方法)。但是我惊讶地发现BaseWriter里面有一个close方法,里面赫然写着“del self.style_list”,这可了得,我虽然不知道它是在什么时候调用了,但是一旦调用了,那不就功亏一篑了,这个列表删掉了那不就全完了。

再看看xlutils.copy库里的内容,找到对应的定义:

class XLWTWriter(BaseWriter):def __init__(self):self.output = []def close(self):if self.wtbook is not None:self.output.append((self.wtname,self.wtbook))del self.wtbook

最终copy函数中的定义中返回的是“w.output[0][1]”,那实际上就是“self.wtbook”这个东西了。

接着找相关定义,可以看到这样一段:

...
self.wtbook = xlwt.Workbook(style_compression=2)
self.wtbook.dates_1904 = rdbook.datemode
self.wtname = wtbook_name
self.style_list = []
...

这可麻烦了呀,wtbook和style_list是BaseWriter类下的两个平级的属性,并没有相互的联系,并且wtbook是一个xlwt.Workbook类型的对象,自然不可能提供获取其父对象的方法(确认了属性也确实没有),这可咋办,进度又陷入了停滞。

于是我又灵机一动,“copy”函数虽然是已经封装好的,但是我也可以把它拆开,就比方说这样:

from xlutils.filter import process, XLRDReader, XLWTWriterrb = xlrd.open_workbook('open.xls', formatting_info=True)
w = XLWTWriter()
process(XLRDReader(rb, 'unknown.xls'), w)
wb = w.output[0][1]

w是一个XLWTWriter类的对象,而XLWTWriter继承于BaseWriter,BaseWriter有style_list属性。那么我尝试访问其style_list属性,也就是“w.style_list”,并按照之前猜想的方法,将sheet.cell_xf_index函数获取到的每个单元格的对应数字,认为是“w.style_list”列表中的查询单元格样式的序列号,写入程序:

style_list = w.style_list
sheet2 = wb.get_sheet(0)
style = style_list[sheet.cell_xf_index(r, c)]
sheet2.write(r, c, sheet.cell_xf_index(r, c), style)

再次打开生成的保存文件,发现格式完美地保留了下来,而内容却如我设定地修改了,至此,程序调试任务完成!

四、终于可以运行的完整代码

完整样例代码是:

可以用xlrd获取打开的Excel的每个单元格的格式,并转化为xlwt写入单元格时支持的XFStyle样式参数。

代码可以实现用xlrd打开Excel后,用xlwt写入单元格内容,而不修改单元格的格式(如果要修改部分原始单元格的格式也可以,只要修改获取到的style的部分属性就可以)

import xlrd
from xlutils.filter import process, XLRDReader, XLWTWriterrb = xlrd.open_workbook('open.xls', formatting_info=True)# 参考xlutils.copy库内的用法 参考xlutils.filter内的参数定义style_list
w = XLWTWriter()
process(XLRDReader(rb, 'unknown.xls'), w)
wb = w.output[0][1]
style_list = w.style_listfor n, sheet in enumerate(rb.sheets()):sheet2 = wb.get_sheet(n)for r in range(sheet.nrows):for c, cell in enumerate(sheet.row_values(r)):style = style_list[sheet.cell_xf_index(r, c)]sheet2.write(r, c, sheet.cell_xf_index(r, c), style)wb.save('save.xls')

用xlwt和xlrd在不修改Excel单元格格式的情况下修改单元格内容相关推荐

  1. excel: 单元格格式修改及绘图

    本期目标:利用excel修改表格格式,如图一. 图1 excel表格格式 原始表格格式如图2: 图2 原始样式 修改步骤包括两步,首先按照"视图--网格线"取消勾选网格线,图3: ...

  2. 如何在 Excel 中复制单元格格式、添加水印?

    欢迎观看 Microsoft Excel 教程,小编带大家学习 Microsoft Excel 的使用技巧,了解如何在 Excel 中复制单元格格式.添加水印. 复制单元格格式,选择要复制的单元格,在 ...

  3. python xlwt设置单元格格式(字体,对齐,边框等)

    xlwt设置单元格格式_幻欢子-CSDN博客_xlwt设置单元格格式# coding:utf-8import patterns as patternsimport xlwtimport timei = ...

  4. WPS——excel单元格格式设置笔记(小白)

    单元格格式设置笔记 选中某一个单元格,按下快捷键Ctrl+1,或者单击鼠标右键,选择设置单元格格式,就可以弹出该卡片啦.如下图共有6个小模块,下面我们一一介绍: 1.数字选项卡 分为12个小类:常规, ...

  5. 杂记(一):Excel对列排序;Rank函数;#N/A;单元格格式转换细节

    文章目录 前言 问题 Excel排序:Rank函数语法 例: 第一个问题:单元格格式未修改成"数值"(如果已设置成"数值"格式仍#N/A,请直接看第二步) 第二 ...

  6. NPOI读取Excel设置单元格格式为数值不生效问题

    初学C#踩坑第一篇 NPOI读取Excel设置单元格格式为数值不生效问题 问题简介: C#使用NPOI写入Excel是修改单元格不能修改,生成后Excel需要打开后双击单元格才会改变格式,话不多说下面 ...

  7. 【Excel VBA】轻松搞定数字、文本单元格格式错乱问题

    纲举目张 说明 代码code 使用说明 说明 在使用Excel的时候最遇到的烦恼就是本来应该是数字的却被认为的文本,导致不能进行计算,本来应该是文本的内容结果被认为是数字,结果显示成了科学计数法,甚至 ...

  8. bigdecimal 保留两位小数_openpyxl修改单元格格式(隐藏小数、设定百分数位数)...

    艺赛旗RPA2020.3.0版本 正在免费下载使用中,欢迎下载使用 艺赛旗-RPA机器人免费下载|提供流程自动化解决方案​www.i-search.com.cn 了解RPA请访问 艺赛旗-RPA机器人 ...

  9. POI设置EXCEL单元格格式为文本、小数、百分比、货币、日期、科学计数法和中文大写...

    再读本篇文章之前,请先看我的前一篇文章,前一篇文章中有重点讲到POI设置EXCEL单元格格式为文本格式,剩下的设置小数.百分比.货币.日期.科学计数法和中文大写这些将在下面一一写出 以下将要介绍的每一 ...

最新文章

  1. 用于道路目标检测的少镜头学习
  2. python哨兵循环_Python:deadloop之非模态交互界面(模态循环)(哨兵循环)
  3. 系统间通信2:通信管理与远程方法调用RMI
  4. C语言之strstr函数
  5. 随想录(windows上cuda环境安装)
  6. Google及其云智慧
  7. SparkStreaming安全消费Kafka数据
  8. 我的Android进阶之旅------gt;Android嵌入图像InsetDrawable的使用方法
  9. (1.4.10)SXF笔试题汇总
  10. HPC高性能计算知识: GPU的工作原理(含视频)
  11. 免费的网站,堪称神器
  12. Fasterrcnn代码个人精细解读(先验框生成部分)
  13. CSS 1px边框问题两个解决方案
  14. selenium使用 webdriver.Chrome() 报错,找不到执行文件的解决方法(一)
  15. mavne更新或新建model后项目的language leval会被重置
  16. w ndows平板插sim卡,HUAWEI MateBookE怎么插入sim卡上网和接收短信?
  17. 005 GO-高级数据类型(结构体和方法)
  18. 基于3dmax及Unity的虚拟博物展览馆
  19. Axure从一个页面向另一个页面传值
  20. 1062 最简分数(JAVA)

热门文章

  1. STM32F4 使用SPI读取气压计MS5611的数据并转化为大气压强
  2. webbench 下载_Ubuntu中webbench安装及简单使用
  3. Microsoft Word中自动编号有参考文献识别不到的问题
  4. 锂电池标3.7V或4.2V的区别
  5. Bentley-Ottmann算法:求N条线段的交点
  6. 16个掘金量化社区的热门话题送给各位Quant的量化交易干货
  7. 华为与IBM员工考核体系的差别
  8. 晶晨方案Burn_Card_Maker工具v2.0.2
  9. bosun 除法使用注意事项
  10. C语言0基础全面教程