天天看點

運用 Range 對象處理 Word 文檔内容

在所有 Office 應用程式中,Microsoft Word 可能是應用最廣泛的應用程式,它還經常在自定義 Office 解決方案中扮演重要的角色。開發人員用各種不同的方式使用 Word,有一些方式很簡單,而另一些極其複雜。無論涉及何種自定義解決方案,用 Visual Basic for Applications (VBA) 處理 Word 文檔的基本方法都是一樣的。下邊,我将概括地介紹如何使用 Word,并提供一些關于如何運用 Range 對象處理 Word 文檔内容的詳細資料。

了解基本方法

在 Word 中,幾乎所有的操作都要調用 Document 對象本身或其内容。當您用 VBA 操作 Word 時,Document 對象表示一個打開的文檔,而且所有的 Document 對象都是 Application 對象的 Documents 集合的成員。

文檔是一個由字元、單詞、句子和段落組成的集合,字元組成單詞,單詞組成句子,句子組成段落,等等。是以,每一個 Document 對象都具有 Characters、Words、Sentences 和 Paragraghs 四個集合。此外,每個文檔具有一個包含一個或多個節的 Sections 集合,每一個節都有一個包含該節頁眉和頁腳的 HeadersFooters 集合。

注意: 您可以在 Microsoft Office 2000 開發人員對象模型指南(英文)中查閱完整的 Word 對象模型。另外,您也可以使用對象浏覽器和 Microsoft Word Visual Basic 參考幫助來學習有關具體某個對象、屬性、方法和事件的詳細内容。

通過 VBA 使用 Word 時,Document 對象處于中心位置。如果您要打開文檔或建立新文檔,就要建立新的 Document 對象。每個打開或新建立的文檔均被添加至 Documents 集合。具有焦點的文檔稱為活動文檔,由 ActiveDocument 屬性表示。

Document 對象作為 Documents 集合中的一個成員,您可以通過使用 Document 對象的索引值(Document 對象在 Documents 集合中的位置,1 是集合中的第一個文檔)或名稱來引用它。另外,您也可以使用 ActiveDocument 屬性來引用目前具有焦點的文檔。例如,如果名為 Policies.doc 的文檔是唯一打開的文檔,則以下三個對象變量将全部指向 Policies.doc:

Dim docOne As Word.Document

Dim docTwo As Word.Document

Dim docThree As Word.Document

Set docOne = Documents(1)

Set docTwo = Documents("Policies.doc")

Set docThree = ActiveDocument

一般情況下不要使用 Documents 集合中的索引值來引用文檔,因為當其它文檔打開或關閉時,某個特定文檔的索引值可能會随之改變。通常,您可以通過使用 ActiveDocument 屬性或使用 Documents 集合的 Add 方法或 Open 方法建立的 Document 對象變量。以下示例顯示了如何使用 ActiveDocument 屬性把一個位址添加到目前具有焦點的文檔中:

With ActiveDocument

   .Envelope.Insert Address:="Office Talk" _

      & vbCrLf & "One Microsoft Way" & vbCrLf _

      & "Redmond, WA 98052", ReturnAddress:= _

      "David Shank" & vbCrLf & _

      "77 First Street" & vbCrLf & _

      "Any Town, USA 12345"

End With

下面的示例說明如何通過使用 Documents 集合的 Open 方法,執行個體化 Document 對象變量。

Dim docPolicy As Word.Document

Set docPolicy = Documents.Open("c:\my documents\policies.doc")

最後一個示例顯示如何通過使用 Add 方法,為新的空文檔建立 Document 對象的執行個體。

Set docPolicy = Documents.Add

通過使用 Open 方法打開的文檔,或者通過使用 Add 方法建立的文檔,都将成為用 ActiveDocument 屬性表示的目前活動文檔。如果您想使 Documents 集合裡的其它文檔成為活動文檔,可使用 Document 對象的 Active 方法。

一旦您擷取了要操作的 Document 對象,絕大部分您想通過 VBA 進行的工作将涉及文本的操作。首先要指定文檔的一個部分,然後對它進行某些操作。例如,添加或删除文本,或者設定單詞或字元的格式。您可以使用 Range 或 Selection 這兩個對象來完成很多工作。在本月的專欄中,我将隻讨論 Range 對象。下個月我們将進一步讨論 Selection 對象的具體内容。

了解 Word 的段落标記

當您通過程式處理文本時,必須了解 Word 如何處理段落标記。從根本上來看,Word 文檔不過是一個巨大的字元流。人們傾向于認為文檔是單詞、句子和段落的集合。但實際上,文檔就是一些字元。每個字元都有一定的作用。某些字元是字母、空格或制表符,另一些字元是段落标記或分頁符。

段落标記在 Word 文檔中扮演獨特的角色,有時這種角色容易被誤解。段落包含一個段落标記以及所有位于此段落标記和前一個段落标記之間的文本(不包括前一個段落标記)。另外,重要的是,段落标記本包含該段落的所有格式資訊。

當複制單詞、句子和段落時,如果包含段落标記,則所有包含在段落标記中的格式資訊也被複制,并在它們被粘貼到其它位置時應用于所屬段落。

如果您想從段落中複制文本并将其粘貼到另一個段落中,但不想同時複制段落格式,複制時請不要包括您要複制的文本旁邊的段落标記。

每個空白的 Word 文檔僅有一個段落标記,其中同時包含 Character 對象、Word 對象、Sentence 對象和 Paragragh 對象各一個。但是,“屬性”對話框(“檔案”菜單)中的“統計資訊”頁籤将報告空白文檔中沒有字元、單詞、句子和段落。這種差異突出顯示了 Word 的一個重要側面,當程式設計操作這些對象時,您需要特别注意這一點。

Range 對象

Range 對象表示文檔中的一個連續範圍,由一個起始字元位置和一個終止字元位置定義。這個連續範圍可以小到一個插入點,大到整個文檔。它也可能是(而非必須是)由目前節表示的範圍。您也可以定義一個 Range 對象,表示和目前節不同的範圍。也可以在同一個文檔中定義多個 Range 對象。Range 對象中的字元包含非列印字元,例如,空格、回車符和段落标記。

使用 Range 對象

建立 Range 對象的典型方法為:聲明一個 Range 類型的對象變量,然後用 Document 對象的 Range 方法或另一個對象(例如 Character、Word、Sentence 或 Selection 對象)的 Range 屬性來執行個體化該變量。例如,以下代碼建立了兩個 Range 對象,均表示活動文檔中的第二個句子。

Dim rngRangeMethod As Word.Range

Dim rngRangeProperty As Word.Range

   If .Sentences.Count >= 2 Then

      Set rngRangeMethod = .Range(.Sentences(2).Start, _

         .Sentences(2).End)

      Set rngRangeProperty = .Sentences(2)

   End If

當您使用 Range 方法來指定文檔的特定範圍時,您必須使用此方法的 Start 參數指定這個範圍開始的位置,使用 End 參數指定結束的位置。文檔的第一個字元的字元位置為 0。最後一個字元的位置和文檔的字元總數相等。您可以通過使用 Characters 集合的 Count 屬性确定文檔中的字元數。如前面的示例所示,您也可以使用 Bookmark、Selection 或 Range 對象的 Start 和 End 屬性來指定 Range方法的 Start 和 End 參數。您可以将 Start 和 End 參數設定為同一個數字,這将建立一個不包含任何字元的範圍。

您可以使用對象的 SetRange 方法設定或重新定義 Range 對象的内容。您也可以通過使用 Range 對象的 Start 屬性或 MoveStart 方法指定或重新定義範圍開始的位置。同樣地,您也可以通過使用 Range 對象的 End 屬性或它的 MoveEnd 方法指定或重新定義範圍結束的位置。

以下示例先用 ContentRagne 對象,該對象包含了文檔的所有内容。接着,改變 EndSetRange 方法重新定義範圍,使之包含文檔的第一個段落。最後,使用 MoveEnd 方法将範圍的結束位置擴充至文檔的第二個段落末尾。此示例中的每一步都将目前範圍中包含的字元的數量列印到“立即視窗”。

Sub RangeExample()

   Dim rngSample As Range

   Set rngSample = ActiveDocument.Content

   With rngSample

      Debug.Print "範圍現在包含 " & .Characters.Count _

         & " 個字元。"

      .End = ActiveDocument.Sentences(1).End

      .SetRange Start:=0, End:=ActiveDocument._

         Paragraphs(1).Range.End

      .MoveEnd Unit:=wdParagraph, Count:=1

   End With

End Sub

您也可以通過使用對象的 Find 屬性傳回 Find 對象,重新定義 Range 對象。以下示例示範用 Find 屬性在活動文檔中确定文本的位置。如果找到了文本,Range 對象将自動重新定義以包含符合搜尋條件的文本。

With rngRangeText.Find

   .ClearFormatting

   If .Execute(FindText:="Find Me!") Then

      ' rngRangeText 被重新定義。

許多 Word 對象具有可傳回 Range 對象的 Range 屬性。在您需要使用 Range 對象的屬性和方法進行操作,而對象本身又不提供這些屬性和方法的情況下,您可以使用對象的 Range 屬性傳回 Range 對象。例如,以下代碼使用 Paragragh 對象的 Range 屬性傳回 Range 對象,進而設定文檔第一個段落中文本的格式:

Dim rngPara As Range

Set rngPara = ActiveDocument.Paragraphs(1).Range

With rngPara

   .Bold = True

   .ParagraphFormat.Alignment = wdAlignParagraphCenter

   .Font.Name = "Arial"

定義 Range 對象後,您可以應用此對象的方法和屬性修改所指定範圍的内容或擷取有關資訊。例如,您可以使用 Range 對象的 StoryType 屬性來确定 Range 在文檔中的位置。

處理 Range 對象中的文本

可以使用 Range 對象的 Text 屬性來指定或确定該範圍包含的文本。例如,以下代碼首先顯示了 Range 對象中的文本,然後更改文本并顯示新文本,最後還原為原始文本。此示例說明了如何使用 Range 對象的 Range 屬性将文本複制和粘貼到文檔中并同時保持原段落結構不變。請注意在 strNewText 變量中包含段落标記 (vbCrLf) 的新文本如何替換在標明原段落時包含的段落标記。

Public Sub ChangeTextSample()

   Dim rngText As Range

   Dim strOriginalText As String

   Dim strNewText As String

   strNewText = "This text is replacing the original" _

      & " text in the first paragraph of the active" _

      & " document. This is all done using only the" _

      & " Text property of the Range object!" & vbCrLf

   Set rngText = ActiveDocument.Paragraphs(1).Range

   With rngText

      MsgBox .Text, vbOKOnly, "This is the original text."

      strOriginalText = .Text

      .Text = strNewText

      MsgBox .Text, vbOKOnly, "This is the new text" _

         & " inserted in paragraph 1."

      .Text = strOriginalText

      MsgBox "The original text is restored."

您可以使用 Range 對象的 StoryType 屬性确定範圍在文檔中的位置。文檔構成部分是指文檔中包含文本的特定範圍。在一個文檔中最多可以有 11 種文檔構成部分,表示正文、頁眉、頁腳、批注等不同範圍。您可以使用 StoryRanges 屬性傳回 StoryRanges 集合。StoryRanges 集合包含 Range 對象,表示文檔中的每一個文檔構成部分。

新 Word 文檔隻包含一個文檔構成部分,稱為“Main Text”,表示文檔主體部分的文本。即使一個空白文檔也包含字元、單詞、句子和段落各一個。

您不需要專門将新文檔構成部分添加至文檔。當您把文本添加至文檔的某個部分(11 種文檔構成部分之一)時,Word 會自動添加它們。例如,如果您要添加頁腳,Word 将添加 Footnotes 文檔構成部分。如果您要添加批注,Word 将把 Comments 文檔構成部分添加到文檔的 StoryRanges 集合中。

您可以使用 Range 屬性傳回 Range 對象來表示文檔中的每一個文檔構成部分。例如,以下代碼列印與 Main Text 和 Comments 文檔構成部分相關的文本:

Dim rngMainText As Word.Range

Dim rngCommentsText As Word.Range

Set rngMainText = ActiveDocument.StoryRanges(wdMainTextStory)

Set rngComments = ActiveDocument.StoryRanges(wdCommentsStory)

Debug.Print rngMainText.Text

Debug.Print rngComments.Text

使用 Range 對象的 InsertBefore 或 InsertAfter 方法,可将文本添加至現有 Range 對象。事實上,有一整類方法,名稱以“Insert”開頭,可以用于操作 Range 對象。

如果有一個過程,能夠把 Range 對象的 InsertBefore 和 InsertAfter 方法與 Text 屬性結合,那麼它将非常有用。在程式設計處理文本時,就可以使用這個過程在同一個地方處理大量工作。以下所示的 InsertTextInRange 正是這樣一個過程。無論何時您需要将文本添加到 Range 對象,都可以調用 InsertTextInRange 過程。換句話說,無論何時您需要在 Word 文檔中程式設計更改現有的文本,這一過程都将非常有用。

InsertTextInRange 過程使用兩個必要的變量和一個可選的變量。strNewText 變量包含您想要添加至 Range 對象的文本,此對象在 rngRange 變量中指定。intInsertMode 可選變量指定将新文本添加至範圍的方式。變量的值是三個自定義枚舉常數中的一個,指定是否使用 InsertBefore 方法、InsertAfter 方法或 Text 屬性替換現有的範圍文本。

Public Enum opgTextInsertMode

    Before

    After

    Replace

End Enum

Function InsertTextInRange(strNewText As String, _

         Optional rngRange As Word.Range, _

         Optional intInsertMode As opgTextInsertMode = _

         Replace) As Boolean

   ' 此過程将 strNewText 參數指定文本插入

   ' rngRange 指定的 Range 對象中。它調用

   ' IsLastCharParagraph 過程從 rngRange 

   ' 對象清除後續的段落标記。

   Call IsLastCharParagraph(rngRange, True)

   With rngRange

      Select Case intInsertMode

         Case 0 ' 在範圍之前插入文本。

            .InsertBefore strNewText

         Case 1 ' 在範圍之後插入文本。

            .InsertAfter strNewText

         Case 2 ' 替換範圍中的文本。

            .Text = strNewText

         Case Else

      End Select

      InsertTextInRange = True

End Function

請注意,在範圍中插入文本之前,使用了 IsLastCharParagraph 過程來删除最後一個段落的段落标記。以下示例使用 Chr$() 函數,以字元代碼 13 表示段落标記。

Function IsLastCharParagraph(ByRef rngTextRange As Word.Range, _

         Optional blnTrimParaMark As Boolean = False) As Boolean

   ' 本過程接受字元、單詞、句子或段落 Range 

   ' 作為第一個參數。如果範圍中的最後一個字元

   ' 是段落标記,則傳回 True;否則傳回 False。

   ' 本過程還接受一個 Boolean 參數,用于指定

   ' 當文本最後存在段落标記時,是否将其删除。

   ' 當 blnTrimParaMark 參數為 True 時,本過

   ' 程調用本身來删除所有後續的段落标記。

   Dim strLastChar As String

   strLastChar = Right$(rngTextRange.Text, 1)

   If InStr(strLastChar, Chr$(13)) = 0 Then

      IsLastCharParagraph = False

      Exit Function

   Else

      IsLastCharParagraph = True

      If Not blnTrimParaMark = True Then

         Exit Function

      Else

         Do

            rngTextRange.SetRange rngTextRange.Start, _

               rngTextRange.Start + _

               rngTextRange.Characters.Count - 1

            Call IsLastCharParagraph(rngTextRange, True)

        Loop While InStr(rngTextRange.Text, Chr$(13)) <> 0

      End If

在此示例中,使用了 Range 對象的 Characters 集合的 Count 屬性來重新定義 Range 對象的終點。

有關處理段落的更多資訊

在前面讨論過的 ChangeTextSample 過程中,請注意 strNewText 變量中的文本如何使用 vbCrLf 内置常量在文本的結束處建立段落标記,進而替換活動文檔的第 1 段中的現有文本。這樣做是為了避免新文檔成為第二個段落的一部分。

當您建立表示 Character、Word 或 Sentence 對象的 Range 對象,并且該對象位于段落的結束位置時,段落标記自動包含在範圍之内。而且,Range 對象将包含後續的空段落标記。例如,在一個由兩個段落組成的文檔中,假設其中第一個段落包含三個句子,而第二個段落為空,那麼以下代碼建立的 Range 對象表示第一段中的最後一個句子:

Set rngCurrentSentence = ActiveDocument.Sentences(3)

因為 rngCurrentSentence Range 對象引用第一個段落的最後一個句子,該段的段落标記(和所有後續的空段落标記)将被自動包含在範圍中。如果您接着将此對象中的 Text 屬性應用到一個沒有使用段落标記結束的文本字元串,那麼文檔中的第二段将被删除。

當您編寫在 Word 文檔中操作文本的 VBA 代碼時,您需要自行處理文本中出現的段落标記。當您在 Range 對象中剪切或粘貼文本時,您可以使用兩種基本方法來處理段落标記:

在要插入文檔的文本中,包含一個新的段落标記(用 vbCrLf 常量表示),如 ChangeTextSample 過程所示。

将最後的段落标記從 Range 對象中排除,如在 InsertTextInRange 過程中 IsLastCharParagraph 函數的應用所示。

繼續閱讀