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

用VBA自动更正错误的注释引用序号

将扫描pdf文件进行文字识别时,对带圈数字表示的注释引用和注释序号往往会将数字序号认错。例如下面的文件:

这个文件的段落十分有规律:每首诗的标题样式为标题3,标题下面的段落为诗的正文,下面有一个样式为标题4的段落,段落文本为【题解】,此段落下面有若干段落进行说明,接下来有一个样式为标题4的段落,段落文本为【校注】,此段落下面有若干个段落为注释,每条注释一段。针对这样布局的文件,可以用下面的VBA程序将注释引用和注释编号的位置全部修改正确:

Sub 更正注释引用与注释序号的编号()
    Dim regEx As Object, aPara As Paragraph, isBody As Boolean, isComm As Boolean
    Dim matches, matche As Object, i%, j%
    Dim searchRange As Range, tmpRange As Range
    
    Set regEx = CreateObject("VBScript.RegExp")
    ' 之所以用正则表达式,是因为超过10的带圈数字序号在VBA编辑器中没法输入
    ' 而Range.Find对象使用的通配符又不支持使用unicode编码
    With regEx
        .Pattern = "[\u2460-\u2473]" ' 1~20带圈数字序号
        .Global = True ' 查找所有匹配
    End With
    i = 1
    Do
        Set aPara = ActiveDocument.Paragraphs(i)
        If aPara.Style = "标题 3" Then ' 遇到诗标题
            i = i + 1 ' 前进一段,进入诗正文
            ' 设定查找区域为正文范围
            Set searchRange = ActiveDocument.Paragraphs(i).Range
            ' 在正文范围内执行匹配
            Set matches = regEx.Execute(searchRange.Text)
            ' 如果存在带圈数字序号,则遍历每一个带圈数字序号,替换为正确的序数
            If matches.Count > 0 Then
                For j = 0 To matches.Count - 1
                    ' 重置查找范围为调整后的范围
                    Set tmpRange = searchRange
                    With tmpRange.Find
                        .Text = matches(j).Value
                        .Wrap = 1 ' wdFindContinue
                        .Execute ' 找到注释引用
                    End With
                    ' 根据循环序数计算出正确的带圈数字序号并替换掉原来的文本
                    tmpRange.Text = ChrW(j + 9312)
                    ' 为防止刚插入的正确带圈数字序号被重复匹配,将查找范围
                    ' 起始位置调整到刚插入的文本之后
                    searchRange.SetRange tmpRange.End, searchRange.End
                Next j
            End If
            i = i + 1
        ' 如过遇到【校注】段落
        ElseIf aPara.Style = "标题 4" And Left(aPara.Range.Text, 4) = "【校注】" Then
            ' 选择此段落
            ActiveDocument.Paragraphs(i).Range.Select
            ' 利用Selection.Bookmarks("\headinglevel")取得此标题及所属段落作为查找区域
            Set searchRange = Selection.Bookmarks("\headinglevel").Range
            ' 在该标题所属段落中进行全局查找
            Set matches = regEx.Execute(searchRange.Text)
            If matches.Count > 0 Then '以下操作与诗正文段落中的操作类似
                For j = 0 To matches.Count - 1
                    Set tmpRange = searchRange
                    With tmpRange.Find
                        .Text = matches(j).Value
                        .Wrap = 1 ' wdFindContinue
                        .Execute ' 找到注释引用
                    End With
                    tmpRange.Text = ChrW(j + 9312)
                    searchRange.SetRange tmpRange.End, searchRange.End
                    ' 因为每条注释一个段落,所以完成一个匹配项替换应该将段落计数器加1
                    i = i + 1
                Next j
                ' 将标题段落的计数也加上
                i = i + 1
            End If
        ' 碰上不是诗标题和注释区标题的段落,直接累加段落计数器。因为诗正文和
        ' 注释段落已在前面处理,所以此处的段落实际上就是题注标题及其所属段落
        Else
            i = i + 1
        End If
    Loop While i < ActiveDocument.Paragraphs.Count '至全文最后一段终止
End Sub

以上代码通用性并不强,只能对特定结构的文档起作用,但仍然演示了正则表达式结合Range.Find进行查找并完成匹配内容定位、查找范围的调整、取得标题及其所属段落区域、数值1-20转换为带圈数字序号(更大的数值大多数字体没有对应的带圈数字序号)等技巧,因而有一定的参考价值。

根据人工智能Kimi的回答,获取标题及其所属段落的Range还有以下方法:

Sub GetTitleAndContentRange()
    Dim doc As Document
    Dim titlePara As Paragraph
    Dim titleRange As Range
    Dim contentRange As Range
    Set doc = ActiveDocument
    ' 获取第一个标题段落
    Set titlePara = doc.Paragraphs(1)
    ' 获取标题段落的 Range
    Set titleRange = titlePara.Range
    ' 扩展范围以包含标题下的所有内容
    Set contentRange = titleRange.Duplicate
    contentRange.Collapse Direction:=wdCollapseEnd
    Do While contentRange.Paragraphs(1).Style <> titlePara.Style
        contentRange.SetRange Start:=contentRange.Start, End:=contentRange.Paragraphs(1).Range.End
        contentRange.Collapse Direction:=wdCollapseEnd
    Loop
    ' 现在 titleRange 包含标题,contentRange 包含标题及其下的内容
    ' 你可以对这些范围进行操作,例如复制、格式化等
End Sub

显然这个方法无论是复杂性还是执行效率都比不上选定标题段落后再使用“Selection.Bookmarks("\headinglevel").Range”获取。上文中要将标题段落本身剔除出searchRange,也只需要再添加一行代码(因为此时标题段落已经被选择):

searchRange.SetRange Selection.Range.End, searchRange.End


http://www.kler.cn/a/457131.html

相关文章:

  • CA系统的设计(CA证书生成,吊销,数字签名生成)
  • Postman测试big-event
  • Logo设计免费生成器工具:轻松创建独特标志
  • 《HelloGitHub》第 105 期
  • 万里数据库GreatSQL监控解析
  • Linux-----进程处理(子进程创建)
  • python圣诞节简单寻宝小游戏
  • Unity功能模块一对话系统(2)打字机淡入效果
  • 喜报 | 擎创科技入围上海市优秀信创解决方案
  • Rancher V2.9.0 Docker安装教程
  • 神经网络入门实战:(二十二)只训练 (多层网络的) 指定层 / (单层网络的) 指定参数
  • 青少年编程与数学 02-005 移动Web编程基础 06课题、响应式设计
  • Web 漏洞之 CSRF 漏洞挖掘:攻防深度剖析
  • SelectionArea 实现富文本
  • 【源码 导入教程 文档 讲解】基于springboot校园新闻管理系统源码和论文
  • 【13】MySQL如何选择合适的索引?
  • 【GlobalMapper精品教程】091:根据指定字段融合图斑(字段值相同融合到一起)
  • C++学习指南
  • 初识MySQL · 库的操作
  • linux内核系列---网络
  • Java圣诞树
  • 数据结构:二叉树部分接口(链式)
  • 力扣算法--求两数之和等于目标数
  • MySQL的TIMESTAMP类型字段非空和默认值属性的影响
  • 用科技的方法能否实现真正的智能
  • DAY3 QT简易登陆界面优化