(二)表格篇(table)(本篇)

选你所需即可。下面开始正文。

上一篇我们讲了用python-docx解析docx文件中的段落,也就是paragraph,不过细心的同学可能发现了,只有自然段是可以用paragraph处理的,如果word中有表格,根本读都读不到。这是正常的,因为表格在docx中是另一个类。

一个word文档中大概有这么几种类型的内容:paragraph(段落),table(表格),character(我也不知道该怎么叫,字符?)。我现在要解析的word文档中,基本都是段落和表格,所以character的具体内容我也没有特别关注。本文主要来讲一下如何从word中解析出表格,并在html中展示出来。

首先,很简单,使用

docx.tables

可以获得文档中的全部表格。跟excel中类似,word文档的表格也是分行(row)和列(column)的,读的方法是,对每一个table,先读出全部的rows,再对每一个row读出全部的column,这里的每行中的一列叫做一个单元格(cell),cell能做到的就跟一个paragraph类似了。如果用不着那么麻烦地获得表格的样式,就直接用

cell.text

获取单元格内容就好了。那么,一个二重循环,就获取到了table中的全部文字内容。

但是这是不够的。我的目的是要在html上展示出来。所以,需要在这一堆内容上添加html标签。具体的做法,我们来举个栗子吧。

不对,拿错了。应该是这样:

这是一个word中的table。按照上面的方法,我们可以写代码如下:

for t indocx.tables:#todo

但其实对于word中的table,并没有这么简单。有的时候,明明这一行只有一列,但是却读出多个值。那么,对于相邻的相同内容,就需要做去重处理。当然,这里的“去重”也不是list(set())这么简单的,因为一行中的所有列应当有顺序。所以,我们采用添加元素的方式:

_table_list =[]for i, row in enumerate(table.rows): #读每行

row_content =[]for cell in row.cells: #读一行中的所有单元格

c =cell.textif c not inrow_content:

row_content.append(c)#print(row_content)

_table_list.append(row_content)

当要添加的元素跟行尾相同时不添加。结果是,上面的tables处理完后,是这样的一堆列表(上面代码中print的位置打印出的结果):

['我们来插入一个表格']

['这是一级标题1', '这是二级标题1.1', '这是三级标题1.1.1', '总结']

['这是一级标题1', '这是二级标题1.1', '这是三级标题1.1.2', '总结']

['这是一级标题1', '这是二级标题1.1', '这是三级标题1.1.3', '总结']

['这是一级标题1', '这是二级标题1.2', '这是三级标题1.2.1', '总结']

['这是一级标题1', '这是二级标题1.3', '这是三级标题1.3.1', '总结']

['这是一级标题1', '这是二级标题1.3', '这是三级标题1.3.2', '总结']

['别忙,还有内容']

['内容', '另一段内容']

不过在去重之后,是没法直接用的……表格是个方格,从整体上来说就是一个矩阵,只是有些位置合并了单元格而已,我们现在的二维数组各列可不是对齐的。所以接下来,需要进行填充处理。填充的方式并没有一腚之龟一定之规,这是因为我们并不知道表格的具体规则如何。好在我要填的表有几本规则:最多4列,如果某一行只有一个元素,就扩充为4个,如果有两个元素,就扩充为前两个元素一致,后两个一致,即[0,1]的列表变成[0,0,1,1]这种形式。没有一行三个元素的时候。我用了一个简单的函数对每行进行了处理,这样每一行都变成了4列,整个二维数组也变成了一个矩阵形式。

我的手动填充代码是这样的:

def_fill_blank(table):

cols= max([len(i) for i intable])

new_table=[]for i, row inenumerate(table):

new_row=[]

[new_row.extend([i]* int(cols / len(row))) for i inrow]print(new_row)

new_table.append(new_row)return new_table

生成的结果是:

['我们来插入一个表格', '我们来插入一个表格', '我们来插入一个表格', '我们来插入一个表格']

['这是一级标题1', '这是二级标题1.1', '这是三级标题1.1.1', '总结']

['这是一级标题1', '这是二级标题1.1', '这是三级标题1.1.2', '总结']

['这是一级标题1', '这是二级标题1.1', '这是三级标题1.1.3', '总结']

['这是一级标题1', '这是二级标题1.2', '这是三级标题1.2.1', '总结']

['这是一级标题1', '这是二级标题1.3', '这是三级标题1.3.1', '总结']

['这是一级标题1', '这是二级标题1.3', '这是三级标题1.3.2', '总结']

['别忙,还有内容', '别忙,还有内容', '别忙,还有内容', '别忙,还有内容']

['内容', '内容', '另一段内容', '另一段内容']

像我这样有规律的表格可以这样做,如果表格毫无规律,就只能听天由命了。

那么,为什么要先去重,再扩充?真的不是吃饱了撑的吗?

原因是,我在我项目中要处理的表,一行里面最多有4列,第一行本来只有1列,结果我读出来了6列。至于为什么会这样,我也不清楚,只能说,用户对于word的用法是五花八门的,只要能做出来想要的样子,就完全没有规矩可言。鬼知道他们是不是把一个4个单元格拆成了6个,又合并成了1个。如果我直接使用6列的结果,是没办法做成html样式的table的。

做扩展的目的,主要是为了合并单元格。在html标签中,用rowspan和colspan来表示跨行和跨列。举个列子,如果一行是跨4列的,这一行应该是

Row One

Row TwoRow TwoRow TwoRow Two

形成这样一个表格:

如果是跨行的,这一列应该是

Right Right Right

形成这样一个表格:

所以,我们的下一步工作就是数数。数清楚在一行中有多少个相同的列,合并到一起,整个矩阵中有多少个相同的行,合并到一起。所谓的合并,就是数量加到上一行/列上去,而本行为空。下图是算法的示意:

合并行:

合并列:

在这样一个二维数组中,每一个元素是一个三元组,第一个元素是表格中的文本内容,第二个元素是rowspan的数量,第三个元素是colspan的数量。如果本行/列跟上一个有内容的行/列内容相同,就把内容加到那一行/列中,本行/列为["", 0, 0];如果不同,则保留。

代码是酱婶的:

def_table_matrix():if nottable:return ""

#处理同一行的各列

temp_matrix =[]for row intable:if notrow:continuecol_last= [row[0], 1, 1]

line=[col_last]for i, j inenumerate(row):if i ==0:continue

if j ==col_last[0]:

col_last[2] += 1line.append(["", 0, 0])else:

col_last= [j, 1, 1]

line.append(col_last)

temp_matrix.append(line)#处理不同行

matrix =[temp_matrix[0]]

last_row=[]for i, row inenumerate(temp_matrix):if i ==0:

last_row.extend(row)continuenew_row=[]for p, r inenumerate(row):if p >=len(last_row):breaklast_pos=last_row[p]if r[0] == last_pos[0] and last_pos[0] != "":

last_row[p][1] += 1new_row.append(["", 0, 0])else:

last_row[p]=row[p]

new_row.append(r)

matrix.append(new_row)return matrix

逻辑上会有一点点难读,在什么情况下数量加1,在哪里加1,需要比较细致地算,否则一定会乱。

最后这个数组出来之后,就可以转化html了。这个很简单,套上tr和td标签即可。代码如下:

deftable2html(t):

table=_fill_blank(t)

matrix=_table_matrix(table)

html= ""

for row inmatrix:

tr= "

for col inrow:if col[1] == 0 and col[2] ==0:continuetd= ["

1:

td.append("rowspan=\"%s\"" % col[1])if col[2] > 1:

td.append("colspan=\"%s\"" % col[2])

td.append(">%s

" %col[0])

tr+= "".join(td)

tr+= "

"html+=trreturn html

我没有套table标签,因为这个可以在页面上调一调样式。不必完全拘泥于word中的样子,也没办法完全按word来——如果一板一眼地按照word的方式设置,出来的html上的table肯定是错乱的,原因嘛,还是在于用户的使用习惯。

最后,要是在jinja模板中使用的话,记得把字符串传到页面上的时候加上safe过滤器。

{{ table|safe }}

出来的表格大概是这样的:

最后我们来对比一下word和table:

如果手工调整一下html table的样式,二者应该可以长得很像的,对吧?

好了,关于table,就介绍这么多。

python table_用python解析word文件(二):table相关推荐

  1. 应用python的docx模块解析word文件内容

    目录 工作问题 涉及知识点 实现过程 目标 调用对应的库和模块 定义通用方法 1.[遍历全部的同格式文件]返回一个文件夹内,限定某类格式文件,返回全部这类文件的绝对路径 2.[提取段落&表格中 ...

  2. Python编程--使用PyPDF解析PDF文件中的元数据

    Python编程–使用PyPDF解析PDF文件中的元数据 元数据 作为一种文件里非常明显可见的对象,元数据可以存在于文档.电子表格.图片.音频和视频文件中.创建这些文件的应用程序可能会把文档的作者.创 ...

  3. python文本筛选多个word_用Python批量替换多个Word文件中的文字

    实例14:用Python批量替换多个Word文件中的文字 公众号"Python操作Office软件高效工作" 29 人赞同了该文章 我们在实例7中批量生成了采购合同.但是假设现在我 ...

  4. word批量替换多组文字 python_实例14:用Python批量替换多个Word文件中的文字

    我们在实例7中批量生成了采购合同.但是假设现在我方的公司名由"ABC商贸有限公司"变成了"ABC贸易有限公司",那我们就需要去每份合同中对应位置进行替换.当然也 ...

  5. 用python解析word文件(三):style

    https://www.cnblogs.com/anpengapple/p/8372991.html 太长了,我决定还是拆开三篇写. (一)段落篇(paragraph) (二)表格篇(table) ( ...

  6. Python批量导入图片到Word文件

    问题背景:2017年4月应华章公司邀请,翻译一本来自美国的Python入门教材,全书共750页,2018年4月完成翻译交稿,2018年9月责任编辑寄来样稿进行印刷前校对.经过半个月的检查和校对,又进行 ...

  7. Python:读取两种Word文件简述及文件未能引发事件错误

    Python 中可以读取 word 文件的库有 python-docx 和 pywin32. 优点缺点python-docx跨平台只能处理 .docx 格式,不能处理.doc格式pywin32仅限 w ...

  8. 「Python」 ElementTree模块解析xml文件,建议小白阅读全文

    背景 Python有三种方法解析xml:SAX,DOM,Elementree.本文记录ElementTree方法解析xml. 目前自己用的是Python3.6,但在该版本中并没有xml的缩进函数ET. ...

  9. python解析xml文件elementtree_在python中使用ElementTree解析xml文件

    ElementTree是python自带的处理xml格式文件的模块,位于libxmletreeElementTree.py.这个模块有两个基本概念:Element和ElementTree. 表示整个树 ...

最新文章

  1. 0x04.基本算法 — 二分和三分
  2. 如何使用万用表测量随机噪声
  3. Spring Security的内置过滤器是如何维护的?
  4. SaltStack:Salt SSH
  5. python zipfile 模块下中文乱码 '╡┌╥╗╒┬_╒╨▒Ω╣½╕µ.docx'
  6. 两个操作字符串的方法:读取指定位置的字符和找出某个字符串的位置
  7. 通过PL/SQL developer工具访问远程的Oracle数据库_访问数据库_连接数据库_登录数据库
  8. Process 执行shell 脚本
  9. 计算机专业最低院校门槛,2021年全国各省高考高校录取最低位次排名查询系统...
  10. 【小错误】ORA-00265: instance recovery required, cannot set ARCHIVELOG mode
  11. Mstsc、Telnet、SSH之间的区别
  12. [JAVA #183; 初级]:1.环境变量的配置
  13. 25 The Go image/draw package go图片/描绘包:图片/描绘包的基本原理
  14. 机器学习- 吴恩达Andrew Ng - week3-3 Multiclass Classification
  15. Google Chrome浏览器模拟设置不同分辨率
  16. TSP问题(推销员问题)
  17. php:php-fpm平滑重启为什么无效
  18. GameFramework:StarForce资源讲解
  19. linux下搭建lamp,Linux下搭建LAMP
  20. python 销售数据分析表格_python数据分析——医院销售数据实战案例

热门文章

  1. Spark 【数据挖掘平台介绍】 - Spark 1.1.0(看范式粒度)
  2. acm国际大学上计算机竞赛,ACM国际大学生程序设计竞赛
  3. deeplink唤醒app测试软件,DeepLink唤醒App的简单实现方法
  4. java继承时父类常量覆盖吗_Java父类继承中的static和final用法
  5. 树叶节点_茶,一片树叶的旅程
  6. 导致网站服务器负担过重,利用httpd.ini实现图片和文件的防盗链
  7. 鸿蒙报名什么时候推送,鸿蒙系统手机版什么时候推送?鸿蒙系统手机版推送时间详解...
  8. php cache-control,网页缓存控制 Cache-control 常见的取值有private、no-cache、max-age、must-revalidate 介绍...
  9. java 数组覆盖_JavaSE——数组集合
  10. 如何在验证集加噪声_如何使用Python构建机器学习模型