用VBA配对引号

最近用百度AI接口识别了一本小说,扫描图片不是很清晰,结果识别出的引号方向大部分不对。就像下面这样:

省略文字”被两个右引号括起来的文字”是一个勾心斗角,相互倾轧的旋涡,人与人之间的关系是一条赤裸裸的利害索链。作者感到压抑、苦闷、愤懑,他只有拿起沉重的笔,抒发心中的“被两个左引号封闭的文字“

小说有112页A4纸,错误的引号数量没有计算,反正手工修改估计可以烦死两个人。粗看了一下,基本上引号都在同一段落中,数量和位置差不多对,只是方向没有匹配好,像这种情况正是VBA大显身手的时候(如果引号位置或数量不对,那VBA很难解决,因为VBA不知道引号该放在哪里,那得靠人工智能来分析自然语言),于是编出了以下代码:

Sub 引号配对()
    Dim oRng As Range
    Dim oDoc As Document, aPara As Paragraph
    Dim iStart, iEnd As Long, needLeft, needRight As Boolean
    Set oDoc = Word.ActiveDocument
    
    Application.ScreenUpdating = False
    
    For Each aPara In oDoc.Paragraphs '一个个段落检查
        needLeft = True '可以有左引号
        needRight = False '不能来右引号
        iEnd = aPara.Range.End '段落末尾索引
        iStart = aPara.Range.start '段落开头索引
        For i = iStart To iEnd - 1
            Set oRng = oDoc.Range(i, i + 1) '逐字符遍历
            If oRng.Text = "“" Then '遇到左引号
                If Not needLeft Then '不需要左引号
                    oRng.Text = "”" '改成右引号
                    needLeft = True '需要左引号
                    needRight = False '不再需要右引号
                Else '需要左引号,不做修改
                    needRight = True '需要右引号配对
                    needLeft = False '不再需要左引号
                End If
            ElseIf oRng.Text = "”" Then '遇到右引号
                If Not needRight Then '不需要右引号
                    oRng.Text = "“" '改成左引号
                    needLeft = False '不再需要左引号
                    needRight = True '需要右引号
                Else '需要右引号,不做修改
                    needLeft = True '需要左引号
                    needRight = False '不再需要右引号
                End If
            End If
        Next
    Next
    
    Application.ScreenUpdating = True
    
End Sub

代码的逻辑注释很详尽,其中有个关键技巧:逐字符遍历段落内容。VBA中没有类似于遍历段落和词那样的for\,each结构用于逐个字符来遍历,这里先取得了段落开始和结尾的字符序号,再使用documentrange方法来取得字符。也许for\ each\ aWord\ in\ aPara.Range.Words这种遍历方式也可以实现上面程序的功能,但是为了记录下逐字符遍历的方法,就没有再试了。

补充:如果先用查找和替换将所有的引号都改成直引号(如果替换后引号仍然是弯引号而不是直引号,那是因为中文版word默认将直引号自动修改为弯引号,需要在word选项的自动更正中将这一选项取消),再用单词(word)遍历的方式,代码可以简化:

Sub 引号配对又一法()
    Dim aW As Word, needLeft, needRight As Boolean
    needLeft = True '需要左引号标志
    needRight = False '需要右引号标志,初始状态下可以有左引号,不能有右引号
    
    Application.ScreenUpdating = False
    
    For Each aW In ActiveDocument.Words
        If aW.Text = """" Then '遍历到直引号
            If needLeft Then '需要左引号
                aW.Text = "“" '改成左引号
                needLeft = False '不再需要左引号
                needRight = True '需要右引号
            ElseIf needRight Then '需要右引号
                aW.Text = "”" '改成右引号
                needRight = False '不再需要右引号
                needLeft = True '需要左引号
            End If
        End If
    Next
    
    Application.ScreenUpdating = True
    
End Sub

运行上面的宏,在我的word2021上出错。这应该是VBA解释器的bug,你不能把aW声明为Word(可能与Word代表这个Application的名称有关)。去掉这条声明语句即可运行成功,但如果是在严格模式下运行VBA,变量又需要预先声明,怎么办呢?经试验,aW声明为Word的父类Range的对象则无论是否严格模式都可以运行成功,即将上述代码第二行的声明语句改为:

Dim aW As Range, needLeft, needRight As Boolean

这段代码的技巧在于用两个直引号才能表示一个直引号。也就是在判断语句“If aW.Text = """" Then”中,等号后面要写4个直引号(""""),而不能是3个直引号("""),如果只用3个直引号,前面两个直引号优先匹配出一个空字符串,后面多了一个没有匹配的直引号,发生语法错误。用4个直引号,中间两个直引号发生转义变成一个直引号,首尾两个直引号表示字符串,于是产生了一个内容为直引号的字符串。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yivifu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值