VBA中按段落遍历Word文档修改段落文本时的正确方法

在Word文档编辑过程中,有时需要对文档的所有段落的内容进行有规律的修改,这时就可以利用VBA来遍历文档所有段落,并对段落进行操作。如果对段落内容的修改不影响到段落的分段符,不会引起什么问题,但是,如果修改涉及分段符,那么结果可能会出乎意料。

例如我们有下面这样一个Word文档:

现在要将上述文档中样式为“标题 2”的段落用HTML标签“<h2></h2>”包裹,样式为“列表段落”的段落用HTML标签“<p class="content"></p>”包裹,样式为“正文”的段落用HTML标签“<p class="comment"></p>”包裹。我们通常想到的VBA代码如下:

Sub test()
    Dim aPara As Paragraph
    For Each aPara In ActiveDocument.Paragraphs
        If aPara.Style = "列表段落" Then
            aPara.Range.Text = "<p class=""content"">" & aPara.Range.Text & "</p>"
        ElseIf aPara.Style = "标题 2" Then
            aPara.Range.Text = "<h2>" & aPara.Range.Text & "</h2>"
        ElseIf aPara.Style = "标题 3" Then
            aPara.Range.Text = "<h3>" & aPara.Range.Text & "</h3>"
        ElseIf aPara.Style = "正文" Then
            aPara.Range.Text = "<p class=""comment"">" & aPara.Range.Text & "</p>"
        End If
    Next aPara
End Sub

执行以后你会发现陷入了死循环。按Ctrl+Break终止运行,会发现宏始终在第一个段落上重复用“<p class="content"></p>”标签包裹“<h2></h2>”标签之间的内容。这主要是因为“aPara.Range.Text = "<h2>" & aPara.Range.Text & "</h2>"”语句将标题段落末尾的分段符删除了,导致此段落与下段并到了一起,段落样式也成了与下段一样的样式,同时,“aPara”变量依然保持着此前标题段落的内容。为了解决这个问题,我们将上面的宏稍微修改一下:

Sub test()
    Dim aPara As Paragraph, i%
    For Each aPara In ActiveDocument.Paragraphs
        i = i + 1
        If aPara.Style = "列表段落" Then
            aPara.Range.Text = "<p class=""content"">" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</p>"
        ElseIf aPara.Style = "标题 2" Then
            aPara.Range.Text = "<h2>" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</h2>"
        ElseIf aPara.Style = "标题 3" Then
            aPara.Range.Text = "<h3>" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</h3>"
        ElseIf aPara.Style = "正文" Then
            aPara.Range.Text = "<p class=""comment"">" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</p>"
        End If
    Next aPara
    Debug.Print i
End Sub

这次不会陷入死循环了,但是整篇文档变成了一个样式为“正文”的段落,并且还插入了4个“<p class="comment">”标签。这是因为插入的内容不包含分段符,导致所有段落的内容合并到了最后一个段落,但“aPara”变量已经正常遍历每一个段落了。现在再做一个修改,在输入的内容末尾添加分段符:

Sub test()
    Dim aPara As Paragraph, i%
    For Each aPara In ActiveDocument.Paragraphs
        i = i + 1
        If aPara.Style = "列表段落" Then
            aPara.Range.Text = "<p class=""content"">" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</p>" & vbCrLf
        ElseIf aPara.Style = "标题 2" Then
            aPara.Range.Text = "<h2>" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</h2>" & vbCrLf
        ElseIf aPara.Style = "标题 3" Then
            aPara.Range.Text = "<h3>" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</h3>" & vbCrLf
        ElseIf aPara.Style = "正文" Then
            aPara.Range.Text = "<p class=""comment"">" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</p>" & vbCrLf
        End If
    Next aPara
    Debug.Print i
End Sub

这次仍然陷入了死循环,中断执行后发现,与第一次不同的是,这次标题段落没有与下一个段落合并到一起,但是标题段落的样式已经变成了与后续段落相同的样式。

以上三次失败无一例外修改时都变动了段落末尾的分段符。实际上,采取“For Each aPara In ActiveDocument.Paragraphs”方式遍历文档时,下一次循环中如果当前段落的分段符发生过变化,“aPara”仍然指向当前段落。对“aPara.Range.Text”赋值的时候,会删除原来的分段符,导致发生段落及样式的合并,这时候如果添加了新的分段符,鉴于原来的分段符发生了变化,“aPara”将始终指向第一个被修改内容的段落,陷入死循环。因此,正确的做法是用“ActiveDocument.Range(aPara.Range.Start, aPara.Range.End - 1)”构造出一个排除了分段符的范围,再修改此范围中的内容。正确的代码如下:

Sub test()
    Dim aPara As Paragraph, paraRng As Range
    For Each aPara In ActiveDocument.Paragraphs
        ' 构造出排除了分段符的文本范围并对其进行赋值
        Set paraRng = ActiveDocument.Range(aPara.Range.Start, aPara.Range.End - 1)
        If aPara.Style = "列表段落" Then
            paraRng.Text = "<p class=""content"">" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</p>"
        ElseIf aPara.Style = "标题 2" Then
            paraRng.Text = "<h2>" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</h2>"
        ElseIf aPara.Style = "标题 3" Then
            paraRng.Text = "<h3>" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</h3>"
        ElseIf aPara.Style = "正文" Then
            paraRng.Text = "<p class=""comment"">" & Left(aPara.Range.Text, Len(aPara.Range.Text) - 1) & "</p>"
        End If
    Next aPara
End Sub

上述代码顺利运行结束,并且所有段落都被正确的标签包裹。参见下图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yivifu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值