当前位置: 首页 > news >正文

按xls标签替换docx及xls内容

WPSoffice环境下,需要批量替换doc文档及xls表格某些内容,在windows下,可以用VBA宏实现,先建一个标签表格,然后按标签批量替换。但在Linux下,WPS表格宏不能跨文档操作WPS文字,于是想用python实现。

1、标签文件与模板文件格式:

标签文件A列为标签名,B列为值。

模板文件关键词用#包围,如下:

2、基本功能

读入标签内容,然后打开模板文件,替换关键词为标签值,保存到新文件。

用到的python库:xlrd、xlutils、tkinter。读入的标签及文件列表使用Treeview展示,并提供修改、增加项、删除项功能。

3、几个重要代码片段

3.1 读xls内容

        # 读入标签表# 打开一个 Excel 文件workbook = xlrd.open_workbook(fname)# 通过索引获取第一个工作表sheet = workbook.sheet_by_index(0)da = []# 遍历所有行和列输出for i in range(sheet.nrows):# 键值分布在1、2列key = str(sheet.cell_value(i, 0)).replace(' ', '')    # 删除空格val = sheet.cell_value(i, 1)date_format = sheet.cell_type(i, 1)# 日期类型if date_format == xlrd.XL_CELL_DATE:date_tuple = xlrd.xldate_as_tuple(val, workbook.datemode)val = '' + str(date_tuple[0]) + "年" + str(date_tuple[1]) + "月" + str(date_tuple[2]) + "日"# 文本类型if date_format == xlrd.XL_CELL_TEXT:val = '' + sheet.cell_value(i, 1)if str(key) != '':da.append((key, val))# print(da)workbook.release_resources()del workbook

3.2 替换docx文档关键词

    def procdocx(self, fname, lbitems, foutname):document = Document(fname)    # 打开文档for paragraph in document.paragraphs:runs = paragraph.runs  # 得到所有runfor i, run in enumerate(runs):key = run.text# 当前run不包含key值if key.count('#') == 0:continuecounter = i  # 记录起始位置if key.count('#') == 1:  # 如先导符与key值分在多个run中while counter < len(runs):  # 将先导符与后续run组成key后再查找counter = counter + 1if counter >= len(runs):breakkey += runs[counter].texttmp = runs[counter].textruns[counter].clear()    # 清空当前runs,本算法会改变文档内容格式if tmp.count('#') > 0:   # 注:如果有多个连续#,且第二个key分在多个run中,会有可能出现替换错误break# 开始替换for item in lbitems:key1 = '#' + self.labeltree.item(item)['values'][0].replace(' ', '') + '#'if key.find(key1) >= 0:# for j in range(i, counter + 1):#    runs[j].clear()key = key.replace(key1, self.labeltree.item(item)['values'][1])runs[i].text = key# 另存到输出文件夹document.save(foutname)

3.3 替换xls表格关键词

    def procxls(self, fname, lbitems, foutname):modxls = xlrd.open_workbook(fname, formatting_info=True)# 将操作文件对象拷贝,变成可写newxls = copy(modxls)# 获取所有sheet页及数量sheets = modxls.sheet_names()for shn in range(len(sheets)):# 通过索引获取第shn个工作表modsheet = modxls.sheet_by_index(shn)newsheet = newxls.get_sheet(shn)# 遍历mod所有行和列输出for i in range(modsheet.nrows):for j in range(modsheet.ncols):val = modsheet.cell_value(i, j)val_format = modsheet.cell_type(i, j)if val_format != xlrd.XL_CELL_TEXT:continue# 开始替换for item in lbitems:key1 = '#' + self.labeltree.item(item)['values'][0].replace(' ', '') + '#'if val.find(key1) >= 0:newval = val.replace(key1, self.labeltree.item(item)['values'][1])newsheet.write(i, j, newval)newxls.save(foutname)

3.4 Treeview代码

1) 创建一个treeview列表

        # 创建 self.labeltree 并添加到 self.mainframe 中columns1 = ("label", "value")self.labeltree = ttk.Treeview(frame51, show="headings", columns=columns1)self.labeltree.column('label', width=100, anchor='w')self.labeltree.heading('label', text="标签名")self.labeltree.column('value', width=300, anchor='w')self.labeltree.heading('value', text="标签值")self.labelscrollx = ttk.Scrollbar(frame51, orient="horizontal", command=self.labeltree.xview)self.labelscrolly = ttk.Scrollbar(frame51, orient="vertical", command=self.labeltree.yview)self.labeltree.configure(xscrollcommand=self.labelscrollx.set)self.labeltree.configure(yscrollcommand=self.labelscrolly.set)self.labelscrollx.pack(side="bottom", fill="x")self.labelscrolly.pack(side="right", fill="y")self.labeltree.pack(expand=1, fill='both', padx='1', pady='1')

2) 双击treeview编辑

    # 双击标签库列表def set_lbcell_value2(self, event):# 获取选中的项目col = self.labeltree.identify_column(event.x)  # 列row = self.labeltree.identify_row(event.y)  # 行if col == '' or row == '':returnselected_item = self.labeltree.selection()[0]cn = int(str(col).replace('#', ''))rn = int(str(row).replace('I', ''))x, y, w, h = self.labeltree.bbox(selected_item, col)txt = self.labeltree.item(selected_item, 'values')[cn-1]edstr = StringVar()edstr.set(txt)entryedit = ttk.Entry(self.labeltree, width=w//8, textvariable=edstr)entryedit.place(x=x, y=y)def saveedit(even):self.labeltree.set(selected_item, column=col, value=edstr.get())entryedit.destroy()entryedit.bind("<FocusOut>", saveedit)# 按下时触发entryedit.bind('<Return>', saveedit)  # 不是Enter而是Return

3) 右击treeview,弹出操作菜单

    # 右击标签库def set_lbcel_popup(self, event):# 创建右键菜单self.right_click_menu = Menu(self.labeltree, tearoff=False)self.right_click_menu.add_command(label="增加", command=lambda: self.on_menu_click_add(event))if self.labeltree.selection():self.right_click_menu.add_command(label="删除", command=lambda: self.on_menu_click_del(event))self.right_click_menu.post(event.x_root, event.y_root)# 新增标签def on_menu_click_add(self, event):self.labeltree.insert('', 'end', values=('新标签', '值'))self.labeltree.update()# 删除标签def on_menu_click_del(self, event):if self.labeltree.selection():self.labeltree.delete(self.labeltree.selection())

4、几个不足之处:

1)python-docx库只能操作docx文件,对doc文档支持不好。

2)对模板文档中标签格式有一定要求,但基本功能已实现。

5、源代码已上传,链接:https://download.csdn.net/download/zhoury/89612390

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • docker-compose笔记
  • Scrapy入门篇
  • 小米账号移除工具箱 | 移除MXTGT工具箱
  • IO流学习总结
  • 定时任务-xxl-job
  • Rabbitmq的死信队列与如何利用死信队列实现延迟队列
  • gitlab-runner /var/run/docker.sock connect permission denied
  • 【Wiki: 使用 netsh wlan show networks mode=bssid | findstr /R /C:“信号“ /C:“频道“ 命令】
  • 基于Python的Bilibili视频信息分析与可视化
  • unfinish ctf 网鼎杯二次注入 无列名注入join-using
  • 无心剑七律《悼李政道先生》
  • 【方法】如何给7Z压缩包添加密码?
  • 大型语言模型入门
  • Linux中Samba服务配置和管理
  • SQL注入 报错注入、文件上传、布尔盲注、时间盲注
  • 3.7、@ResponseBody 和 @RestController
  • Android交互
  • IP路由与转发
  • leetcode388. Longest Absolute File Path
  • spark本地环境的搭建到运行第一个spark程序
  • vue数据传递--我有特殊的实现技巧
  • Yeoman_Bower_Grunt
  • 阿里云购买磁盘后挂载
  • 编写符合Python风格的对象
  • 干货 | 以太坊Mist负责人教你建立无服务器应用
  • 码农张的Bug人生 - 见面之礼
  • 入口文件开始,分析Vue源码实现
  • 为物联网而生:高性能时间序列数据库HiTSDB商业化首发!
  • 学习使用ExpressJS 4.0中的新Router
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 异步
  • 湖北分布式智能数据采集方法有哪些?
  • ​力扣解法汇总946-验证栈序列
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • #etcd#安装时出错
  • (160)时序收敛--->(10)时序收敛十
  • (4) PIVOT 和 UPIVOT 的使用
  • (Qt) 默认QtWidget应用包含什么?
  • (第27天)Oracle 数据泵转换分区表
  • (十五)使用Nexus创建Maven私服
  • (算法)Travel Information Center
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • .bat批处理(二):%0 %1——给批处理脚本传递参数
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .Net 转战 Android 4.4 日常笔记(4)--按钮事件和国际化
  • .net对接阿里云CSB服务
  • .NET使用存储过程实现对数据库的增删改查
  • .NET微信公众号开发-2.0创建自定义菜单
  • @RequestBody与@ModelAttribute
  • [ 渗透测试面试篇 ] 渗透测试面试题大集合(详解)(十)RCE (远程代码/命令执行漏洞)相关面试题
  • [7] CUDA之常量内存与纹理内存
  • [Algorithm][动态规划][路径问题][不同路径][不同路径Ⅱ][珠宝的最高价值]详细讲解