手动解析word Table模块内容
最近来了一个需求, 需要手动解析word ( 好处就是不需要安装office 以及不会有office解析的线程残留),然后就是可以自定义解析规则,比较方便
比如解析这个word里面的内容: 标题,表格的行和列,以及单元格里面的每一个项

解决方案
使用 DocumentFormat.OpenXml.dll + WindowsBase.dll+正则表达式
WindowsBase.dll 和 DocumentFormat.OpenXml.dll 都是微软的,
可以不用安装office 就能得到 对应的 文档( word,excel) 的 xml格式文本内容,缺点是 只支持 docx,xlsx ,
低版本的(doc,xls)读不出来(可能是未按照对应的协议进行排版),
另外再说一个比较 麻烦的问题, 金山wps和 office ,以及其他厂商的,对 word文件 的内部实现不一样,解析的话需要做兼容处理.
以下是主要的对象以及方法:(仅供参考)
//引入命名空间
using System.Text.RegularExpressions;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using (WordprocessingDocument doc = WordprocessingDocument.Open(stream, false))
{
Body body = doc.MainDocumentPart.Document.Body; foreach (var xmlElement in body.Elements<OpenXmlElement>())
{
List<string> RowElement = new List<string>();
foreach (var item in xmlElement.ChildElements)
{
string elementText = item.InnerText.Trim();
if (!string.IsNullOrEmpty(elementText))
{
//处理 elementText
RowElement.Add(elementText);
}
}
}
} string bodyInnerXml = body.InnerXml;
//然后通过 正则表达式 "<w:tbl(\\s|>)(.+?)</w:tbl>" 得到 table的个数 /*2.解析 table 对应的 单元格数据*/
foreach (var table in body.Elements<Table>())
{
string t_table_xml = table.InnerXml;
//通过正则 "<w:tr(\\s|>)(.+?)</w:tr>"); 匹配行的个数
//通过正则"<w:tr(\\s|>)(.+?)</w:tr>", "<w:tc>(.+?)</w:tc>" 匹配列的个数 }
//遍历行
foreach (var tableRow in table.Elements<TableRow>())
{
string rowInnerText = tableRow.InnerText;
//遍历列
foreach (var tableCell in tableRow.Elements<TableCell>())
{
//凡是实现了IEnumerable接口的类,都可以使用foreach循环迭代遍历, 不过很遗憾,没有提供 this[index] 的访问方式
string celInnerXml = tableCell.InnerXml;
//要解析 单个item项的内容. 只能通过 正则表达式了, 不同的厂商, 里面的xml内容是不一样的, 所以要做很多的兼容....
if ((celInnerXml.Contains("<w:numPr>")|| celInnerXml.Contains("w:pPr>"))&& celInnerXml.Contains("</w:p>"))
{
//1.目前来说是这样做兼容的
//2.然后通过正则 "<w:numPr(\\s|>)(.+?)</w:p>" 和 "<w:pPr(\\s|>)(.+?)</w:p>" 判断是否有对应的 匹配项
//3.就算得到了 匹配项,. 里面还有很多的样式代码,要把这些样式代码都替换掉(通过正则 @"<(.[^>]*)>" 进行替换)
//4.另外还有各种有序符号,无序符号,以及 checkbox框( □ ) 等 标识符, 这些字符贴到网页上 的code值好像都是9633
// 5.在 word里面 无序符号 是通过特殊的标签定义的,不同厂商的标签不一样,要识别不同厂商的只能做兼容处理
} } }
贴3个比较有用的方法
/// <summary>
/// 去除所有Html标签,以及换行,制表符
/// </summary>
/// <param name="Htmlstring">要格式化的字符串</param>
/// <returns></returns>
public static string NoHTML(string Htmlstring) //去除HTML标记
{
//删除脚本
Htmlstring = Regex.Replace(Htmlstring, @"<script.+?</script>", "", RegexOptions.Multiline | RegexOptions.IgnoreCase);
//删除HTML
Htmlstring = Regex.Replace(Htmlstring, @"<(.[^>]*)>", "", RegexOptions.IgnoreCase); Htmlstring = Regex.Replace(Htmlstring, @"-->", "", RegexOptions.IgnoreCase);
Htmlstring = Regex.Replace(Htmlstring, @"<!--.*", "", RegexOptions.IgnoreCase); Htmlstring = Regex.Replace(Htmlstring, @"&(quot|#34);", "/", RegexOptions.IgnoreCase);
Htmlstring = Regex.Replace(Htmlstring, @"&(amp|#38);", "&", RegexOptions.IgnoreCase);
Htmlstring = Regex.Replace(Htmlstring, @"&(lt|#60);", "<", RegexOptions.IgnoreCase);
Htmlstring = Regex.Replace(Htmlstring, @"&(gt|#62);", ">", RegexOptions.IgnoreCase);
Htmlstring = Regex.Replace(Htmlstring, @"&(nbsp|#160);", " ", RegexOptions.IgnoreCase);
Htmlstring = Regex.Replace(Htmlstring, @"&(iexcl|#161);", "/xa1", RegexOptions.IgnoreCase);
Htmlstring = Regex.Replace(Htmlstring, @"&(cent|#162);", "/xa2", RegexOptions.IgnoreCase);
Htmlstring = Regex.Replace(Htmlstring, @"&(pound|#163);", "/xa3", RegexOptions.IgnoreCase);
Htmlstring = Regex.Replace(Htmlstring, @"&(copy|#169);", "/xa9", RegexOptions.IgnoreCase);
Htmlstring = Regex.Replace(Htmlstring, @"&#(/d+);", "", RegexOptions.IgnoreCase);
Htmlstring = Regex.Replace(Htmlstring, @"\r\n|\n|\t", ""); return Htmlstring;
}
public static string NoXml(string xmlString,string replaceEmpty="")//去除xml标记
{
//删除脚本
// xmlString = Regex.Replace(xmlString, @"<script.+?</script>", "", RegexOptions.Multiline | RegexOptions.IgnoreCase);
//删除<>标签内的内容
xmlString = Regex.Replace(xmlString, @"<(.[^>]*)>", "", RegexOptions.IgnoreCase);
if (replaceEmpty.Length>0)
{
xmlString = xmlString.Replace(replaceEmpty, "");
}
xmlString = xmlString.Replace("□", "");
return xmlString;
}
/// <summary>
/// 得到所有(.+?)匹配到的集合
/// </summary>
/// <param name="regexStr">带(.+?)的正则表达式</param>
/// <param name="inputHtml">Html源代码</param>
/// <returns></returns>
public static List<string> GetMatchRegexList(string regexStr, string inputHtml)
{
List<string>list = new List<string>();
StringBuilder sbulider = new StringBuilder();
if (!string.IsNullOrEmpty(regexStr))
{
Regex regex = new Regex(regexStr, RegexOptions.Singleline | RegexOptions.IgnoreCase);
if (regex.IsMatch(inputHtml))
{
MatchCollection mc = regex.Matches(inputHtml);
for (int i = 0; i < mc.Count; i++)
{
list.Add(mc[i].Groups[0].Value);
}
}
}
return list;
}
GetInnerHtml(p_text:string):string{
//p_text = p_text.replace(//g,"@rn");
p_text = p_text.replace(/□/g,''); //这个是 9633
p_text = p_text.replace(/<span style="white-space:pre">/g,'@rn');//兼容处理
p_text = p_text.replace(/<br>/g,'@rn');//换行
p_text = p_text.replace(/<\/br>/g,'@rn');//换行
p_text = p_text.replace(/<\/p>/g,'<\/p>@rn');//换行
p_text = p_text.replace(/<(.[^>]*)>/g,'');//去除<>标签块的内容
p_text = p_text.replace(/@rn /g,'@rn'); //兼容处理
p_text = p_text.replace(/n /g,''); //兼容处理,一些稀奇古怪的东西
p_text = p_text.replace(/@rn/g,'@rn');//多个换行,替换为一个换行
//... 其他的兼容性代码
return p_text;
}
//其他代码
// console.log(("□".charCodeAt(0))); //无序符号,粘贴到网页里面, 变成了 这个字符, 经测定,该字符的 code值 为 9633
另外如果是 直接将word里面的内容, 粘贴到 网页上的div里面, 然后获取innerHTML 代码, 传到后台, 需要做一下预处理
比如我这里标记换行, 用的是 "@rn" 字符
手动解析word Table模块内容的更多相关文章
- 解析word中的表格
由于word表格的特殊性,其本身中的数据本来就不够完善,不能够很好的知道其具体的合并.跨行的相关属性,表格的单位可能是PT或者是百分比,并且是共存的,为处理带来了一定的负担,本代码实现了一个将Word ...
- Java解析word文档
背景 在互联网教育行业,做内容相关的项目经常碰到的一个问题就是如何解析word文档. 因为系统如果无法智能的解析word,那么就只能通过其他方式手动录入word内容,效率低下,而且人工成本和录入出错率 ...
- 用python解析word文件(三):style
太长了,我决定还是拆开三篇写. (一)段落篇(paragraph) (二)表格篇(table) (三)样式篇(style)(本篇) 选你所需即可.下面开始正文. 在前两篇中,我们已经解析出了par ...
- 用python解析word文件(一):paragraph
太长了,我决定还是拆开三篇写. (一)段落篇(paragraph)(本篇) (二)表格篇(table) (三)样式篇(style) 选你所需即可.下面开始正文. 最近公司的项目,需要在页面上显示w ...
- php解析word,获得文档中的图片
背景 前段时间在写一个功能:用原生php将获得word中的内容并导入到网站系统中.因为文档中存在公式,图片,表格等,因此写的比较麻烦. 思路 大体思路是先将word中格式为doc的文档转化为docx, ...
- 如何手动解析vue单文件并预览?
开头 笔者之前的文章里介绍过一个代码在线编辑预览工具的实现(传送门:快速搭建一个代码在线编辑预览工具),实现了css.html.js的编辑,但是对于demo场景来说,vue单文件也是一个比较好的代码组 ...
- python 解析XML python模块xml.dom解析xml实例代码
分享下python中使用模块xml.dom解析xml文件的实例代码,学习下python解析xml文件的方法. 原文转自:http://www.jbxue.com/article/16587.html ...
- Apache-Tika解析Word文档
通常在使用爬虫时,爬取到网上的文章都是各式各样的格式处理起来比较麻烦,这里我们使用Apache-Tika来处理Word格式的文章,如下: package com.mengyao.tika.app; i ...
- 【爬虫入门手记03】爬虫解析利器beautifulSoup模块的基本应用
[爬虫入门手记03]爬虫解析利器beautifulSoup模块的基本应用 1.引言 网络爬虫最终的目的就是过滤选取网络信息,因此最重要的就是解析器了,其性能的优劣直接决定这网络爬虫的速度和效率.Bea ...
随机推荐
- 2016 ZCTF note3:一种新解法
2016 ZCTF note3:一种新解法 最近在学习unlink做到了这道题,网上有两种做法:一种是利用edit功能读入id时整数溢出使索引为-1,一种是设置块大小为0使得写入时利用整数溢出漏洞可以 ...
- Bing 广告平台迁移到 .net6
原文链接 https://devblogs.microsoft.com/dotnet/bing-ads-campaign-platform-journey-to-dotnet-6/ 广告组件平台对于微 ...
- 记一次某制造业ERP系统 CPU打爆事故分析
一:背景 1.讲故事 前些天有位朋友微信找到我,说他的程序出现了CPU阶段性爆高,过了一会就下去了,咨询下这个爆高阶段程序内部到底发生了什么? 画个图大概是下面这样,你懂的. 按经验来说,这种情况一般 ...
- NLP之基于BERT的预测掩码标记和句间关系判断
BERT @ 目录 BERT 程序步骤 程序步骤 设置基本变量值,数据预处理 构建输入样本 在样本集中随机选取a和b两个句子 把ab两个句子合并为1个模型输入句,在句首加入分类符CLS,在ab中间和句 ...
- Selenium4.0+Python3系列(四) - 常见元素操作(含鼠标键盘事件)
一.写在前面 上篇文章介绍的是关于浏览器的常见操作,接下来,我们将继续分享关于元素的常见操作,建议收藏.转发! 二.元素的状态 在操作元素之前,我们需要了解元素的常见状态. 1.常见元素状态判断,傻傻 ...
- Linux--多线程(三)
生产者消费者模型 概念: 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过一个来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给 ...
- 野火 STM32MP157 开发板内核和设备树的编译烧写
一.环境 编译环境:Ubuntu 版本:18.4.6 交叉编译工具:arm-linux-gnueabihf-gcc 版本:7.4.1 开发板:STM32MP157 pro 烧写方式:STM32Cube ...
- 京东云开发者|软件架构可视化及C4模型:架构设计不仅仅是UML
软件系统架构设计的目标不在于设计本身,而在于架构设计意图的传达.图形化有助于在团队间进行高效的信息同步,但不同的图形化方式需要语义一致性和效率间实现平衡.C4模型通过不同的抽象层级来表达系统的静态结构 ...
- 介绍一个jmeter录制脚本谷歌插件 —— metersphere-chrome-plugin
该插件可将用户在浏览器操作时的 HTTP 请求记录下来并生成 JMX 文件(JMeter 脚本文件). 1. 插件解压 插件下载链接: https://pan.baidu.com/s/14nGb_s9 ...
- 2022-11-02 Acwing每日一题
逆序对的个数 给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量. 逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆 ...