1. はじめに
ワードで作成した文書に、ある特定の文字列(集合)に蛍光マーカーで着色したいと思ったことはないだろうか。たとえば作成していた資料の校正を行うために用語のゆらぎを調べたり、あるいは目次を作るために索引語をマーキングしたりと、用途はいろいろありそうだ(Fig.1参照)。
Fig.1 蛍光マーキングの例 本文以外に2つのテキストエリア内もマーキングしている。
ネットでその方法を検索すると、あるにはあるのだが、それでやってみても本文だけはマーキングできるのだが、図形オブジェクトのテキストアリア内に打ち込んだ文章にはマーキングされないなどいろいろトラブルに出くわした経験はないだろうか。
テキストアリアも処理対象にしたいと検索キーワードに「ワード VBA テキストエリア 文字列 蛍光マーカー」など入力して検索するのだがなかなか的を射たコンテンツが見つからない。ChatGPTに尋ねても嘘ばかり教えられる。そういった経験はないだろうか。
そういった方々のために私が悪戦苦闘した解決方法を備忘録として書き留めることにした。
2. 概要
要点は Selection
オブジェクトの Find
メソッドで指定した文字列を検索し、Selection.Range.HighlightColorIndex
に蛍光マーカーの色番号を設定するだけである。とはいえ、不慣れな人には何をしてよいのやらわからない。そこで、具体例を交えながら一つずつ説明していく。
2.1 Selection オブジェクト
Selection
オブジェクトは文字列をマーキングする際のターゲット(Word文書本体なのか図形オブジェクトのテキストエリアなのか)である。Select
メソッドでターゲットを選択して、あとはSelection
オブジェクトを使って検索文字列を Find
し、見つかったら Find
オブジェクトの Execute
メソッドを見つかった数だけ繰り返して蛍光ペンの色を設定する(たとえば黄色の蛍光ペンなら Selection.Range.HighlightColorIndex = wdYellow
)だけだ。
具体的な例を示そう。
With Selection.Find
Selection.Move wdStory
.Text = buf
.Replacement.Text = buf
.Wrap = wdFindContinue
Do While .Execute
Selection.Range.HighlightColorIndex = wdYellow
Loop
End With
ここで、buf
は蛍光マーキングしたい文字列である。
では、Selection
オブジェクトはいまどこをターゲットにしているのだろうか?本文だろうか?それとも図形オブジェクトのテキストエリアだろうか?
実はそのターゲットは意識して選択(Select
)しなければならない。何も書かずに上記のコードを実行すると文書本体がターゲットになるみたいだ。通常は文書本体しかマーキングする必要性を感じないだろうからこれで片が付く。しかし、凝った文書を作成して図形オブジェクトのテキストエリアを多用して、重要な内容をその中に詰め込んだらどうなるだろう?上記のコードはテキストエリアの中までマーキングしてくれない。
そこで登場するのが Select
メソッドである。
2.2 Select オブジェクト
Select
オブジェクトはターゲットを選択する。たとえばWordの文書本体であれば
ActiveDocument.Range.Select
とすればよい。ここで、ActiveDocument
は現在アクティブになっている文書である。Word文書内のマクロであれば、今開いているWord文書それ自身だ。だが、普通こんなものは書かない。書かないでも文書に付属するマクロが実行する時点で現在開いている文書のドキュメント(本体)がSelect
されているからだ。しかし、たまたま何か処理で別のオブジェクトがSelect
されていたらどうなるだろう?コード1は一生懸命そのSelect
されたオブジェクトにマーキングしようとすることだろう。だから、その場合の安全策として本文を対象としたい場合はいつでもコード1に先立ってコード2を書いておけばよい。
では、図形オブジェクトのテキストアリアをSelect
するにはどうすればよいか。コード3がそれである。
For Each shp In ActiveDocument.Shapes
If shp.Type = msoTextBox Then
shp.TextFrame.TextRange.Select
Call [任意の蛍光マーキング処理]
End If
Next
ActiveDocument.Shapes
は現在開いているWord文書のすべての図形オブジェクトを表すコレクションで、そこから一つずつShape
オブジェクトをshp
に取り出してShape
オブジェクトのTextFrame
オブジェクトの中にあるTextRange
オブジェクトをSelect
メソッドで選択する。それがshp.TextFrame.TextRange.Select
である。ただし、コード3ではShape
オブジェクトのType
プロパティで図形オブジェクトがテキストエリア(msoTextBox
)であることを確認してからターゲットに選択している。やっていないのでわからないが、他のオブジェクト(たとえば矩形オブジェクト)でも、その中にテキスト領域があればこのコードでマーキングができるかもしれない。こうしてターゲットが選択(Select
)できたら任意の蛍光マーキング処理を呼び出す。
3. WordマクロとExcelマクロ
さて、概要が分かったところで実際にコードを作っていこう。その際、考えなければならないのは、そのコードをどこに書くかである。どこに、というのはWordファイルそのものにか、それともVBAが利用できる他のファイル、たとえばExcelファイルにか、ということである。
もっとも簡単なのはWordファイルそのものに書くことである。これまで紹介したコードはすべてWordファイル本体に書くコードを想定していた。しかし、Word本体にコードを書くと様々な問題点が出てくる。まず最初に、これが一番問題となるが、ファイルの種類をWordファイル(.docx
ファイル)ではなくマクロ付きWordファイル(.docm
ファイル)に変換しなければならない。自分の自由にしてよいWordファイルならともかく、チーム内や公に共有(公開)するファイルだとまず無理である。
そこで、次善の策として、VBAが利用できるOffice関連ファイル、あるいはVBScriptを利用することが考えられる。ここでは最もVBAが利用しやすいExcelファイルを用いる例を紹介する。
3.1 Wordマクロ
Wordマクロを使う場合、前準備として2つの作業がある。一つ目は、前述したように、ファイルの種類をWordファイル(.docx
ファイル)からマクロ付きWordファイル(.docm
ファイル)に変換すること、二つ目はメニューに[開発]ボタンを表示することである。Word で [開発] タブを表示するにはこのサイトを参考に設定を行なえばよいだろう。
[開発]ボタンをクリック後、VIsualBasicエディタを開いて新規に標準モジュールを作成して次のコードを入力する。
Option Explicit
Sub 蛍光マーキング()
Dim strArray() As String
strArray = Split("急性骨髄性白血病:白血病", ":")
Call 本文蛍光マーキング(strArray)
Call テキストエリア蛍光マーキング(strArray)
End Sub
Sub 本文蛍光マーキング(strArray() As String)
ActiveDocument.Range.Select
Call 選択蛍光マーキング(strArray)
End Sub
Sub テキストエリア蛍光マーキング(strArray() As String)
Dim shp As Shape
For Each shp In ActiveDocument.Shapes
If shp.Type = msoTextBox Then
Debug.Print shp.Name
'Debug.Print shp.TextFrame.TextRange.Text
shp.TextFrame.TextRange.Select
Call 選択蛍光マーキング(strArray)
End If
Next
End Sub
Sub 選択蛍光マーキング(strArray() As String)
Dim buf As Variant
For Each buf In strArray
With Selection.Find
Selection.Move wdStory
.Text = buf
.Replacement.Text = buf
.Wrap = wdFindContinue
Do While .Execute
Selection.Range.HighlightColorIndex = wdYellow
Loop
End With
Next
End Sub
メイン関数はSub 蛍光マーキング()
で、まず、マーキングする文字列配列strArray
を組み立てたのちに本文をマーキングするプロシージャ本文蛍光マーキング(strArray)
を呼び出し、ついで図形オブジェクトのテキストアリアをマーキングするテキストエリア蛍光マーキング(strArray)
を呼び出す。
本文蛍光マーキング(strArray)
は、マーキング文字列配列strArray
を受け取り、ActiveDocument.Range.Select
で本文を選択(Select
)したのちに共通「マーキング」ルーチン選択蛍光マーキング(strArray)
を呼び出す。
テキストエリア蛍光マーキング(strArray() As String)
はマーキング文字列配列strArray
を受け取り、ActiveDocument.Shapes
から図形オブジェクトを一つずつ取り出して変数shp
に格納し、それがテキストアリア(msoTextBox
)であればshp.TextFrame.TextRange.Select
によってテキストアリアを選択(Select
)し、共通「マーキング」ルーチン選択蛍光マーキング(strArray)
を呼び出す。
共通「マーキング」ルーチン Sub 選択蛍光マーキング(strArray() As String)
では受け取ったマーキング文字列配列 strArray
から一つずつ文字列を取り出して変数 buf
に格納し、それを Selection.Find
メソッドで検索し、見つかったら Find````オブジェクトの
Executeメソッドで
Selection.Range.HighlightColorIndex = wdYellow によって黄色(
wdYellow```)にマーキングする。
3.2 Excelマクロ
Excelマクロを使う場合、前準備として3つの作業がある。最初の2つはWordマクロと同様にファイルの種類の変更(.xlsx
ファイルから.xlsm
へ)と[開発]ボタンの表示で、残る一つは参照設定である。これは、Excel から Word オブジェクトを参照するための設定で、これをやっておくとコードのオートフィルが有効になり、効率的であると同時にミスタイプ防止や発見的コーディングが可能となって嬉しい。ネットで検索するプログラムの中には参照設定を行わず、何でもかんでも Object で宣言する例をよく見るが私は好きではない。さて、その参照設定だが、Visual Basic エディタ(略してVBエディタ)のメニュー画面から[ツール]→[参照設定]→[Microsoft Word 16.0 Object Library]にチェックを入れる。ただし、16.0 の部分はマシン依存なので適宜読み替えて欲しい。
さて、準備が整ったら、新規に標準モジュールを作成して次のコードを入力する。
Option Explicit
Sub 蛍光マーキング()
Dim wdApp As Word.Application
Dim wdDoc As Word.Document
Dim strArray() As String
' Wordアプリケーションを開く
Set wdApp = New Word.Application
wdApp.Visible = False
' Word文書を開く
Set wdDoc = wdApp.Documents.Open(ActiveWorkbook.path & "\サンプル.docm")
' 病名を":"で区切る
strArray = Split("急性骨髄性白血病:白血病", ":")
' 蛍光マーキング
Call 本文蛍光マーキング(wdApp, strArray)
Call テキストエリア蛍光マーキング(wdApp, strArray)
' Word文書を保存して閉じる
wdDoc.Save
wdDoc.Close
' Wordアプリケーションを終了
wdApp.Visible = True
wdApp.Quit
End Sub
Sub 本文蛍光マーキング(wdApp As Word.Application, strArray() As String)
wdApp.ActiveDocument.Range.Select
Call 選択蛍光マーキング(wdApp, strArray)
End Sub
Sub テキストエリア蛍光マーキング(wdApp As Word.Application, strArray() As String)
Dim shp As Word.Shape
For Each shp In wdApp.ActiveDocument.Shapes
If shp.Type = msoTextBox Then
Debug.Print shp.Name
'Debug.Print shp.TextFrame.TextRange.Text
shp.TextFrame.TextRange.Select
Call 選択蛍光マーキング(wdApp, strArray)
End If
Next
End Sub
Sub 選択蛍光マーキング(wdApp As Word.Application, strArray() As String)
Dim buf As Variant
For Each buf In strArray
With wdApp.Selection.Find
wdApp.Selection.Move wdStory
.Text = buf
.Replacement.Text = buf
.Wrap = wdFindContinue
Do While .Execute
wdApp.Selection.Range.HighlightColorIndex = wdYellow
Loop
End With
Next
End Sub
Word マクロとの違いに留意して説明する。もっとも大きな違いは、Excel で Word 文書を操作するには Word アプリケーションオブジェクト Word.Application
を使う。 また、処理対象の Word ドキュメントをインスタンス化するために Word ドキュメントオブジェクト Word.Document
を使う。両者はメイン関数 Sub 蛍光マーキング()
で定義しインスタンス化する。コード5では、各々 wdApp
と wdDoc
という名前で定義している。Word ドキュメントオブジェクト wdDoc
は Word アプリケーションオブジェクト wdApp
の Documents.Open
メソッドを使ってインスタンス化する。引数には Word 文書ファイルを指定する。ActiveWorkbook.path
は現在この Excel ファイルが格納されているパスが返されるので、Excel ファイルと同じフォルダに格納された Word 文書ファイル サンプル.docm
が開かれる。
マーキングする文字列配列strArray
を組み立てたのちに本文をマーキングするプロシージャ本文蛍光マーキング(wdApp, strArray)
を呼び出し、ついで図形オブジェクトのテキストアリアをマーキングするテキストエリア蛍光マーキング(wdApp, strArray)
を呼び出すのは Word マクロの場合と同様である。違うのは、各々のプロシージャの第一引数に Word アプリケーションオブジェクト wdApp
が引き渡されている点である。これはマーキング処理のターゲットを選択(Select
)する際に必要となる。なぜなら、Word マクロでは対象とする Word 文書は ActiveDocument
で参照できたが、Excel マクロではそれが wdApp.ActiveDocument
となるからである。これを考慮して本文をマーキングするプロシージャ Sub 本文蛍光マーキング(wdApp As Word.Application, strArray() As String)
とテキストアリアをマーキングするプロシージャ Sub テキストエリア蛍光マーキング(wdApp As Word.Application, strArray() As String)
を修正する。
最後に、共通「マーキング」ルーチン Sub 選択蛍光マーキング(wdApp As Word.Application, strArray() As String)
も Word アプリケーションオブジェクト wdApp
を受け取る。これは Selection
オブジェクトが Word のものだと明確に指定するためである(単に Selection
とすると、それは Excel の Selection
オブジェクトとみなされる)。
全ての蛍光マーキング処理が終了したら、Word 文書を保存して閉じてから Word アプリケーションを終了させる。
4. おわりに
作成したマクロを使って Word のサンプル文書に対して蛍光マーキングを行った結果が Fig.1 である。この文書には本文以外に2つのテキストエリアがあるが、指定した文字列(この場合は「急性骨髄性白血病」と「白血病」)が本文に対してもテキストエリアに対しても蛍光マーキングされているのがわかる。
今回紹介した蛍光マーキングに限らず、Word 文書に対して様々な処理を行う際に、いちいち Word 文書にマクロを書くのは運用面でも得策ではなく Excel ファイルを Word 文書のハンドラとして利用することが多いのではないか思う。その際のテンプレートとして今回紹介した Excel マクロが利用できるのではないかと思う。