VSTO中Word的查找方式

前言

使用C#在VSTO开发Word插件的过程,经常需要对文档中的内容进行查找和替换。在Word中进行文本的查找替换,和一般对纯文本的查找替换却不太一样。因为Word文档是一个富文本对象,对文本的查找实际上是对一个对象的查找,而这个或者这种对象对于开发者是未知不可见的,因此和纯文本搜索比较,不仅存在许多不一样的地方,也存在一定的难度。本文主要对这些差异进行了讨论和分析。

正则全文搜索

通常情况下,对一个文本进行查找,我们会使用正则表达式,找到匹配模式的位置,如下所示。

    var pattern = "[0-9]+?";var content = "第1个";var mc = System.Text.RegularExpressions.Regex.Matches(content, pattern);if (mc.Count > 0){foreach (System.Text.RegularExpressions.Match m in mc){//获取匹配字符串在输入中的索引位置int searchIndex = m.Index;}}

而在Word文档中,我们可以通过range.Text属性获取到文档的字符串表示,利用相同的正则表达式来进行查找。

    var pattern = "[0-9]+?";//获取文档的全部字符var content = doc.Range().Text;var mc = System.Text.RegularExpressions.Regex.Matches(content, pattern);if (mc.Count > 0){foreach (System.Text.RegularExpressions.Match m in mc){//获取匹配字符串在输入中的索引位置int searchIndex = m.Index;}}

如果这个文档都是由纯文本组成的,那么得到的位置,就是查找字符在全文中的真实位置。
然而实际上大多数情况下,文档还可能有图片、表格、公式和图表等格式组成,不仅仅是文本组成。

range位置的替换

Word在将文档转换成Text的过程中,如果格式是文本,那么一个字符A就将转换成一个字符A(复制);如果格式是富文本对象,比如图片,那个一个图片将会转换成一个空字符串“ ”,仅表示位置。
然而,在Word文档中,纯字符串类型的range的长度就是字符串的长度;非字符串对象的range的长度不确定。所以,经过Text的转换后,range的位置信息缺少了。查找到字符串在Text的位置,并不能找到该字符串在全文的range位置,也就无法对查找的字符串进行操作了。

//*表示任意字符,range长度为1
//A表示一个图片,range长度为4
//B表示一个公式,range长度为6//Word文档中全文的range位置
****A**B**
(1)(2)(3)(4)(8)(9)(10)(17)(18)(19)//Text的位置, 如图
**** ** **
(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)

既然字符串的range位置丢失了,索性事先把所有对象的位置先存储起来。

/// <summary>
/// 从range中获取每一个字符的实际位置
/// </summary>
/// <param name="range">选中部分</param>
/// <returns>位置列表</returns>
public List<int> GetRangeLocation(Word.Range range)
{var ret = new List<int> { };foreach (Word.Range c in range.Characters){ret.Add(c.Start);}return ret;
}

利用位置信息,终于可以得到一个可以正确查找文本的方法了。

/// <summary>
/// 根据模式,找到所有匹配的位置
/// </summary>
/// <param name="range">选中部分</param>
/// <param name="pattern">模式</param>
/// <returns>匹配列表</returns>
public List<Word.Range> SearchRangeInPattern(Word.Range range, string pattern)
{var ret = new List<Word.Range> { };var content = range.Text;var doc = range.Document;//获取实际的字符位置var locationList = GetRangeLocation(range);var mc = System.Text.RegularExpressions.Regex.Matches(content, pattern);if (mc.Count > 0){foreach (System.Text.RegularExpressions.Match m in mc){var searchStart = m.Index;var searchEnd = m.Index + m.Value.Length;//将text位置转换为range位置var realStart = locationList[searchStart];var realEnd = locationList[searchEnd];//获取匹配的range位置var itemRange = doc.Range(realStart, realEnd);ret.Add(itemRange);}}return ret;}

实际运用

在实际运用的过程中,基本不能采用这种全文的正则查找方式,除非要搜索的文本内容长度很小。因为经过测试,获取字符的实际range位置,具有非常大的时间开销。原因在于获取每一个字符都是一次COM调用,调用时间数量级在10毫秒左右。多次的COM调用,使得总调用时间非常大。

find和replace的API查找

在Word的API存在定义好的查找函数,可以使用Word定义的规则(类似于正则表达式)的方式,进行通配符查找。

/// <summary>
/// 替换选中部分的文字
/// </summary>
/// <param name="range">选中部分</param>
/// <param name="search">待替换文字</param>
/// <param name="replace">替换文字</param>
public static void SearchReplace(Word.Range range, string search, string replace)
{range.Find.ClearFormatting();range.Find.Text = search;//使用通配符搜索range.Find.MatchWildcards = true;range.Find.Replacement.ClearFormatting();range.Find.Replacement.Text = replace;object replaceAll = Word.WdReplace.wdReplaceAll;object missing = Type.Missing;range.Find.Execute(ref missing, ref missing, ref missing, ref missing, ref missing,ref missing, ref missing, ref missing, ref missing, ref missing,ref replaceAll, ref missing, ref missing, ref missing, ref missing);
}

使用这种方法,查找速度快,执行时间短。
但是缺点也很明显,匹配经常不准确,比如空格和换行符,由于图片的悬浮位置影响,无法匹配。
此外基于通配符的匹配,毕竟不是正则表达式,不支持零字符位匹配和or匹配,所以用处有限,许多功能无法实现。

\\捕获0-无限个数字,
[0-9]* //正则表达式,若干个数字,包括0个
[0-9]{1,} //Word,若干个数字,必须1个以上\\捕获数字或者字母
[0-9]|[a-z] //正则表达式,一个数字或一个字母
[0-9] then [a-z] //word,只能分成两次来匹配,不支持or的匹配

总结对比

方式 查找速度 匹配准确度 匹配模式
正则全文搜索 非常慢, 多次COM调用 正则表达式,类型多,只支持文本
Find查找 快,一次COM调用 通配符,类型少,支持多种对象查找

转载于:https://www.cnblogs.com/senhtry/p/9324015.html

VSTO中Word的查找方式相关推荐

  1. python环绕文字_Java 设置 Word 文档中图片文字环绕方式

    Java 设置 Word 文档中图片文字环绕方式 在Word文档中插入图片时,选择合理的图片文字环绕方式可以使图片的展示效果更好,也能使页面的排版更加美观.本文就将介绍如何使用Free Spire.D ...

  2. PHP将数组存入数据库中的四种方式

    最近突然遇到了一个问题,如何用PHP将数组存入到数据库中,经过自己的多方查找和研究,总结了以下四种方法: 1.implode()和explode()方式 2.print_r()和自定义函数方式 3.s ...

  3. word高级查找替换应用

    ** word高级查找替换应用 ** 实例1:在一篇长文档中,如果要在很多地方添加同一个公式或图片. 首先在需要输入公式的地方输入"gongshi".再在另一文档中输入该公式并选中 ...

  4. 使用FindAncestor查找方式绑定且不需要使用datacontext

    使用FindAncestor查找方式绑定且不需要使用datacontext 原文:使用FindAncestor查找方式绑定且不需要使用datacontext <UserControl x:Cla ...

  5. php 数组存入mysql_PHP将数组存入数据库中的四种方式

    1.implode()和explode()方式 2.print_r()和自定义函数方式 3.serialize()和unserialize()方式 4.json_encode()和json_decod ...

  6. html相同标签nth,详解CSS nth-child与nth-of-type的元素查找方式

    nth-child和nth-of-type是css的两个伪选择符.应用中,这两者常常容易混淆.这里把它们拿出来仔细做个对比,看看这两者是怎么查找元素的. nth-child(n) -- 寻找第n个子元 ...

  7. linux中的五大查找命令---whereis,find,locate,which,type

    附代码上色实例: <table><tr><td bgcolor=#7FFFD4> <ol> <li><font size=" ...

  8. Javascript中的对象查找【转】

    编辑点评:本文作者为大家介绍Javascript中的对象查找一些问题,希望有所帮助. 近期群里常有人提一些简单的问题,比如发一段代码乱七八糟的代码,然后说里面某个变量是什么,比如这里就有个很好的例子: ...

  9. Notepad++中的高级查找

    准备以下字符串用来演示 abcdeab cdeabcde abcd eabcde 基于扩展的查找 基于扩展的查找不能算是真正的正则表达式搜索,因此这种查找方式仅是提供了支持转义字符.主要常用的转义字符 ...

最新文章

  1. 天龙源码分析 - 选择角色流程
  2. oracle表空间 unifor,Oracle 表空间的监控
  3. 01 前端篇(标签)
  4. QT获取本地网络信息
  5. 200919阶段一C++STL容器
  6. 哈工大大数据实验_【新闻动态】南京大学PASA大数据实验室在KDD Cup 2020 AutoGraph自动化图数据建模国际挑战赛中荣获第二名...
  7. Tomcat下work文件夹的作用
  8. java正则表达式中的斜杠,java正则表达式匹配斜杠[Java编程]
  9. unity摄像头实物识别_“千万别让女朋友擦倒车摄像头,太tm可怕了哈哈哈哈哈!”...
  10. linux内核贡献排名,谷歌ARM靠边站!Linux内核贡献,华为反超Intel全球第一
  11. mysql的配置管理_MySQL 启动流程及配置管理
  12. 你说啥什么?注解你还不会?
  13. 春天到了,讲讲Spring的工作原理
  14. hive sql 向上取整、向下取整、保留小数位的函数
  15. c语言while if嵌套,C语言循环嵌套详解
  16. Elasticsearch分析器(analyzer)以及与spring boot整合
  17. HackTheBox::Bashed
  18. secure CRT脚本命令用于记录屏显日志
  19. 卸载Android系统中自带的应用
  20. 单片机c语言程序开发洗衣机,基于51单片机的洗衣机程序

热门文章

  1. HDU 1865 1string
  2. 软文写作技巧,你的微信软文也能破100000+
  3. Response.setContentType类型按文件扩展名首字母分类大全
  4. Android TextView带背景图片和自定义边框
  5. 服务器ip导致微信域名红,微信/QQ域名检测-最新腾讯域名检测官方接口
  6. 流式数据、批式数据、实时数据、历史数据的区别
  7. 创业者如何克服困难,控制焦虑情绪,走向成功
  8. spreadsheet php,关于 PhpSpreadsheet 简单教程
  9. Springboot毕设项目企业财务管理系统lmm93java+VUE+Mybatis+Maven+Mysql+sprnig)
  10. 我对于测试团队建设的意见