简体   繁体   English

在 MS Word 中遍历段落并修剪空格

[英]Iterate through paragraphs and trim spaces in MS Word

I need to create a macros which removes whitespaces and indent before all paragraphs in the active MS Word document.我需要创建一个宏来删除活动 MS Word 文档中所有段落之前的空格和缩进。 I've tried following:我试过以下:

For Each p In ActiveDocument.Paragraphs
    p.Range.Text = Trim(p.range.Text)
Next p

which sets macros into eternal loop.将宏设置为永恒循环。 If I try to assign string literal to the paragraphs, vba always creates only 1 paragraph:如果我尝试为段落分配字符串文字,vba 总是只创建 1 个段落:

For Each p In ActiveDocument.Paragraphs
    p.Range.Text = "test"
Next p

I think I have a general misconception about paragraph object.我想我对段落对象有一个普遍的误解。 I would appreciate any enlightment on the subject.我将不胜感激任何有关该主题的启示。

The reason the code in the question is looping is because replacing one paragraph with the processed (trimmed) text is changing the paragraphs collection.问题中的代码循环的原因是因为用处理过的(修剪过的)文本替换一个段落正在改变段落集合。 So the code will continually process the same paragraph at some point.所以代码会在某个时候不断地处理同一个段落。

This is normal behavior with objects that are getting deleted and recreated "behind the scenes".这是在“幕后”被删除和重新创建的对象的正常行为。 The way to work around it is to loop the collection from the end to the front:解决它的方法是将集合从末尾循环到前面:

For i = ActiveDocument.Paragraphs.Count To 1 Step -1
    Set p = ActiveDocument.Paragraphs(i)
    p.Range.Text = Trim(p.Range.Text)
Next

That said, if the paragraphs in the document contain any formatting this will be lost.也就是说,如果文档中的段落包含任何格式,这将丢失。 String processing does not retain formatting.字符串处理不保留格式。

An alternative would be to check the first character of each paragraph for the kinds of characters you consider to be "white space".另一种方法是检查每个段落的第一个字符,以查找您认为是“空白”的字符类型。 If present, extend the range until no more of these characters are detected, and delete.如果存在,扩展范围直到不再检测到这些字符,然后删除。 That will leave the formatting intact.这将保持格式不变。 (Since this does not change the entire paragraph a "normal" loop works.) (因为这不会改变整个段落,所以“正常”循环有效。)

Sub TestTrimParas()
    Dim p As Word.Paragraph
    Dim i As Long
    Dim rng As Word.Range

    For Each p In ActiveDocument.Paragraphs
        Set rng = p.Range.Characters.First
        'Test for a space or TAB character
        If rng.Text = " " Or rng.Text = Chr(9) Then
            i = rng.MoveEndWhile(" " + Chr(9))
            Debug.Print i
            rng.Delete
        End If
    Next p
End Sub

You could, of course, do this in a fraction of the time without a loop, using nothing fancier than Find/Replace.当然,您可以在没有循环的情况下在很短的时间内完成此操作,只需使用 Find/Replace 即可。 For example:例如:

Find = ^p^w
Replace = ^p

and

Find = ^w^p
Replace = ^p

As a macro this becomes:作为一个宏,这变成:

Sub Demo()
Application.ScreenUpdating = False
With ActiveDocument.Range
  .InsertBefore vbCr
  With .Find
    .ClearFormatting
    .Replacement.ClearFormatting
    .Forward = True
    .Wrap = wdFindContinue
    .Format = False
    .MatchWildcards = False
    .Text = "^p^w"
    .Replacement.Text = "^p"
    .Execute Replace:=wdReplaceAll
    .Text = "^w^p"
    .Execute Replace:=wdReplaceAll
  End With
  .Characters.First.Text = vbNullString
End With
Application.ScreenUpdating = True
End Sub

Note also that trimming text the way you're doing is liable to destroy all intra-paragraph formatting, cross-reference fields, and the like;另请注意,按照您的方式修剪文本可能会破坏所有段落内格式、交叉引用字段等; it also won't change indents .它也不会改变缩进 Indents can be removed by selecting the entire document and changing the paragraph format;可以通过选择整个文档并更改段落格式来删除缩进; better still, modify the underlying Styles (assuming they've been used correctly).更好的是,修改底层样式(假设它们已被正确使用)。

Entering "eternal" loop is a bit unpleasant.进入“永恒”循环有点不愉快。 Only Chuck Norris can exit one.只有查克诺里斯可以退出。 Anyway, try to make a check before trimming and it will not enter:无论如何,尝试在修剪之前进行检查,它不会进入:

Sub TestMe()

    Dim p As Paragraph
    For Each p In ThisDocument.Paragraphs
        If p.Range <> Trim(p.Range) Then p.Range = Trim(p.Range)
    Next p

End Sub

As has been said by @Cindy Meister, I need to prevent endless creation of another paragraphs by trimming them.正如@Cindy Meister 所说,我需要通过修剪来防止无休止地创建另一个段落。 I bear in mind that paragraph range contains at least 1 character, so processing range - 1 character would be safe.我记住段落范围至少包含 1 个字符,因此处理范围 - 1 个字符是安全的。 Following has worked for me以下对我有用

Sub ProcessParagraphs()
    Set docContent = ActiveDocument.Content

    ' replace TAB symbols throughout the document to single space (trim does not remove TAB)
    docContent.Find.Execute FindText:=vbTab, ReplaceWith:=" ", Replace:=wdReplaceAll

    For Each p In ActiveDocument.Paragraphs

        ' delete empty paragraph (delete operation is safe, we cannot enter enternal loop here)
        If Len(p.range.Text) = 1 Then
            p.range.Delete

        ' remove whitespaces
        Else
            Set thisRg = p.range
            ' shrink range by 1 character
            thisRg.MoveEnd wdCharacter, -1
            thisRg.Text = Trim(thisRg.Text)
        End If

        p.LeftIndent = 0
        p.FirstLineIndent = 0
        p.Reset
        p.range.Font.Reset

    Next

    With Selection
        .ClearFormatting
    End With
End Sub

I saw a number of solutions here are what worked for me.我在这里看到了许多对我有用的解决方案。 Note I turn off track changes and then revert back to original document tracking status.注意我关闭跟踪更改,然后恢复到原始文档跟踪状态。

I hope this helps some.我希望这对一些人有所帮助。

Option Explicit

Public Function TrimParagraphSpaces()
       
    Dim TrackChangeStatus: TrackChangeStatus = ActiveDocument.TrackRevisions
    ActiveDocument.TrackRevisions = False
    
    Dim oPara As Paragraph
    For Each oPara In ActiveDocument.StoryRanges(wdMainTextStory).Paragraphs
        Dim oRange As Range: Set oRange = oPara.Range
        Dim endRange, startRange As Range
        
        Set startRange = oRange.Characters.First
        Do While (startRange = Space(1))
            startRange.Delete 'Remove last space in each paragraphs
            Set startRange = oRange.Characters.First
        Loop
    
        Set endRange = oRange
        ' NOTE: for end range must select the before last characted. endRange.characters.Last returns the chr(13) return
        endRange.SetRange Start:=oRange.End - 2, End:=oRange.End - 1
        Do While (endRange = Space(1))
            'endRange.Delete 'NOTE delete somehow does not work for the last paragraph
            endRange.Text = "" 'Remove last space in each paragraphs
            Set endRange = oPara.Range
            endRange.SetRange Start:=oRange.End - 1, End:=oRange.End
        Loop
     Next
     
    ActiveDocument.TrackRevisions = TrackChangeStatus
End Function

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM