我做了一个c#的docx函数库。
python操作word实在是太垃了,尤其是涉及到多表、页眉页脚,甚至有时候好好的段落硬是搜不到。所以我转向了对于word操作支持更好的c#。
说是讲实现,实际上只讲了使用。毕竟实现挺复杂的也不好讲,不如感兴趣的自己看源码吧。我这里直接讲讲怎么用我这个函数就好了。
github resourcehere: kasusa/Docx_Search
简介
本库主要适用于docx文件的修改、段落搜索、表格搜索等,填补了官方未提供的“搜索”功能的空白。
功能主要包括:
- word中所有图片提取为bitmap
- 搜索段落
- 搜索表格
- 删除段落
- 获取单元格(cell)的内容
- 批量替换
- 保存到桌面 out文件夹
依赖
本库是基于开源*非商用的docx库编写的。引用如下两个库,可以在这里下载:xceedsoftware/DocX ,这个项目提供了一些非常实用的例子,建议新手先看他们的例子来学习c#操作word的逻辑。
1using Xceed.Document.NET;
2using Xceed.Words.NET;
创建对象
我把官方的document对象又封装了一遍,这样使用函数的时候更加直观。
1myutil tempo;//我的word对象
2//docx文件的路径
3string tempo_path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @$"\Sample\方案\方案A.docx";
4if (System.IO.Directory.Exists(tempo_path))
5{
6 //初始化对象
7 tempo = new myutil(a);
8}
搜索段落
搜索段落如同word中一样,使用string作为关键字进行搜索,实现下来整体速度还不错。
有的时候一篇word中搜索一个关键词可能有好几个结果,这种时候返回list的就派上用场了。
有的时候可能要操作的段落不好定位,但是可以确定他在某个标题的下面,index搜索就派上用场了,返回的index+1差不多就是需要的段落位置了。
注意:xceed.docx的实现比较完善,可以搜索到目录、表格中的段落,所以有时候搜索错了可能是搜索到目录里面了……
我写了几种类型的搜索函数:
1Find_Paragraph_for_p(string v) //搜索后返回paragraph
2Find_Paragraph_for_plist(string v) //搜索后返回paragraph列表
3Find_Paragraph_for_text(string v) //搜索后返回string(段落的文字内容)
4Find_Paragraph_for_i(string v) //搜索后返回段落的index
5Find_Paragraph_for_ilist(string v) //搜索后返回段落的index list
举一个实际的例子:
1//搜索“本报告记录编号:”,返回段落的text
2tmpstr = doc.Find_Paragraph_for_text("本报告记录编号:");
3//获取到:本报告记录编号:P2021XXXXX-GB01。
4//处理切分一下字符串,获取到我需要的部分
5tmpstr = myutil.get_string_after(tmpstr, "本报告记录编号:", "P2021XXXXX".Length);//结果:P2021XXXXX
再举一个例子:
1//搜索总体评价(一级标题),获取其后面段落的内容
2int i = doc.Find_Paragraph_for_ilist("总体评价")[0] + 1;
3a = doc.document.Paragraphs[i].Text;
搜索的时候如果得到的结果不是很正常,就要看看word中是不是又多个能搜到的位置了。
搜索表格
搜索表格是一个我自创的功能,他是利用表头(首行)的文字内容对整个word中的所有表标题进行检索,如果某一个表格的第一行和给的参数相同,就认为是查找到了这张表。
经过我的实际测试,速度还算可以。
1//寻找表头文字为“序号 机房名称 物理位置 重要程度”的第一张表
2//注意这里我没有删除空格和tab,这是为了从word中复制过来方便,实际在函数中会把空格、tab字符都删除后进行对比
3var table1 = doc.findTableList("序号 机房名称 物理位置 重要程度")[0];
下面是我实现的一个表格复制函数。从word1中把t1复制到t2,可以选择是否包含表头。
1#region 表格复制函数
2/// <param name="t1head">table1 表头</param>
3/// <param name="i1">table1 所在index</param>
4/// <param name="t2head">table2 表头</param>
5/// <param name="i2">table 2 所在index</param>
6void CopyTable(string t1head, string t2head, int i1 = 0, int i2 = 0)
7{
8 bool toremove = false;
9 var table1 = doc.findTableList(t1head)[i1];
10 ConsoleWriter.WriteColoredText("table 报告中 ↑", ConsoleColor.Green);
11 var table2 = tempo.findTableList(t2head)[i2];
12 ConsoleWriter.WriteColoredText("table 模板中 ↑", ConsoleColor.Green);
13 //如果t1比t2更宽,增加一列临时列
14 if (table1.ColumnCount > table2.ColumnCount)
15 {
16 table2.InsertColumn();
17 toremove = true;
18 }
19 //如果t1比t2更窄,直接给t2瘦身
20 else if (table1.ColumnCount < table2.ColumnCount)
21 {
22 table2.RemoveColumn(table2.ColumnCount-1);
23 }
24 //删除所有空的内容行
25 while (table2.RowCount > 1)
26 {
27 table2.RemoveRow(table2.RowCount - 1);
28 }
29 //从内容行数开始复制
30 for (int i = 1; i < table1.RowCount; i++)
31 {
32 Xceed.Document.NET.Row row = table1.Rows[i];
33
34 table2.InsertRow(row);
35 }
36 //删除多复制过来的列
37 if (toremove)
38 {
39 table2.RemoveColumn(table2.ColumnCount - 1);
40 }
41 ConsoleWriter.WriteColoredText("复制表完毕;", ConsoleColor.Yellow);
42
43}
44
45/// <summary>
46/// 复制表t1到表t2(包含表头)
47/// </summary>
48/// <param name="t1head">table1 表头</param>
49/// <param name="i1">table1 所在位数</param>
50/// <param name="t2head">table2 表头</param>
51/// <param name="i2">table 2 所在位数</param>
52void CopyTable_withHead(string t1head, string t2head, int i1 = 0, int i2 = 0)
53{
54 bool toremove = false;
55 var table1 = doc.findTableList(t1head)[i1];
56 ConsoleWriter.WriteColoredText("table 报告中 ↑", ConsoleColor.Green);
57 var table2 = tempo.findTableList(t2head)[i2];
58 ConsoleWriter.WriteColoredText("table 模板中 ↑", ConsoleColor.Green);
59 //如果t1比t2更宽,增加一列临时列
60 if (table1.ColumnCount > table2.ColumnCount)
61 {
62 table2.InsertColumn();
63 toremove = true;
64 }
65 //如果t1比t2更窄,直接给t2瘦身
66 else if (table1.ColumnCount < table2.ColumnCount)
67 {
68 table2.RemoveColumn(table2.ColumnCount - 1);
69 }
70 //删除所有空的内容行
71 while (table2.RowCount > 1)
72 {
73 table2.RemoveRow(table2.RowCount - 1);
74 }
75 //从内容行数开始复制
76 for (int i = 0; i < table1.RowCount; i++)
77 {
78 Xceed.Document.NET.Row row = table1.Rows[i];
79
80 table2.InsertRow(row);
81 }
82 //删除多复制过来的列
83 if (toremove)
84 {
85 table2.RemoveColumn(table2.ColumnCount - 1);
86 }
87 //删除顶部的原始行(表头总是有问题服了)
88 table2.RemoveRow(0);
89 ConsoleWriter.WriteColoredText("复制表完毕;", ConsoleColor.Yellow);
90
91}
92
93#endregion
文字批量替换
文字批量替换是我参考官方文档的例子写出来的,因为功能很常用所以把他包含到了库中。
1//向字典里面添加【被替换str】、【替换成str】
2doc._replacePatterns.Add("P2021xxxxx", "P202100001");
3doc._replacePatterns.Add("AAAAA", "可口可乐公司");
4
5doc.ReplaceTextWithText_all_noBracket();//自动搜索文档中所有在字典里面的内容并替换
明天过生日啦~