マーカ部分をRange配列として取得する(Word)
Findオブジェクトを用いてマーカ部分を取得する
この記事
へのid:imihitoさんのコメントにより、Find
オブジェクトを用いて「蛍光ペン」のところをRange
オブジェクトとして取得できるということを知った。
参考にしたのは『みんなのワードマクロ』様。
WordVBAのFind
オブジェクトというやつは、どうもイメージしづらくて苦手だったんだが、この際だからまじめに取り組んでみようと思った。
いや、実は過去に一度、非常にまじめに取り組んだことがあるんですけどね……。
マーカ部分を配列にして返すFunction
マーカ部分をRange
オブジェクトの配列として保持しておけば、あとはそのHighlightColorIndex
プロパティを切り替えるだけで網掛けの有無を切り替えることができる。
Find
オブジェクトを使って検索すると、ヒットした部分が選択された状態になるので、Selection
オブジェクトという形で取得が可能になる。
その都度、Range
型の配列にぶち込んで行けば良いと思った。
リスト1 標準モジュール
Public Function getHighLightedRange( _ ByVal targetDocument As Document) As Range() Application.ScreenUpdating = False Dim targetRange As Range '……(1)' Set targetRange = Selection.Range Call targetDocument.Range(0, 0).Select '……(2)' Call Selection.Find.ClearFormatting '……(3)' Call Selection.Find.Replacement.ClearFormatting With Selection.Find '……(4)' .Text = "" .Replacement.Text = "" .Forward = True .Wrap = wdFindContinue .Format = False .Highlight = True .MatchCase = False .MatchWholeWord = False .MatchByte = False .MatchAllWordForms = False .MatchSoundsLike = False .MatchWildcards = False .MatchFuzzy = False End With Call Selection.Find.Execute '……(5)' Dim ar() As Range '……(6)' Dim i As Long i = 0 Do While Selection.Find.Found '……(7)' ReDim Preserve ar(i) Set ar(i) = Selection.Range i = i + 1 Call Selection.Collapse(Direction:=wdCollapseEnd) Call Selection.Find.Execute Loop Call targetRange.Select '……(8)' getHighLightedRange = ar Application.ScreenUpdating = True End Function
(1)の
Dim targetRange As Range Set targetRange = Selection.Range
は、コード実行時のカーソル位置を覚えさせておくだけのもの。
(8)の
Call targetRange.Select
で、コード開始時のカーソル位置にカーソルを置くため。
別になくても構わないが、これをしておかないと、実行するたびにカーソルが最後にヒットした場所に行くことになる。
(2)の
Call targetDocument.Range(0, 0).Select
で、文書の先頭にカーソルを置く。
(3)からの2行
Call Selection.Find.ClearFormatting Call Selection.Find.Replacement.ClearFormatting
は、Find
オブジェクトの初期化。
で、大事なのは次。
(4)からの14行
With Selection.Find '……(4)' .Text = "" .Replacement.Text = "" .Forward = True .Wrap = wdFindContinue .Format = False .Highlight = True .MatchCase = False .MatchWholeWord = False .MatchByte = False .MatchAllWordForms = False .MatchSoundsLike = False .MatchWildcards = False .MatchFuzzy = False End With
で、Find
オブジェクトの設定。
たくさんプロパティがあるが、綴り字でだいたい何を設定しているのかは見当が付くと思う。
Forward
プロパティとHighlight
プロパティだけがTrue
になっているのが分かると思う。
これを、
これと見比べれば、今回何をどう設定したのかが分かると思う。
これでFind
オブジェクトの設定は終わったので、あとは(5)の
Call Selection.Find.Execute
でFind
オブジェクトのExecute
メソッドを実行する。
これは、上の画像の[次を検索]をクリックするのと同じ(Find.Forward
プロパティがTrue
なので)。
まず、この時点で
こうなる。一つ目のマーカ部分が選択された状態。
ここからが処理の第二段階。
(6)からの3行
Dim ar() As Range Dim i As Long i = 0
で、ヒットしたRange
オブジェクトを受ける配列を準備。要素数が確定しないので、動的に宣言しておく。変数i
は、後にReDim
するために使う。
(7)からの7行
Do While Selection.Find.Found ReDim Preserve ar(i) Set ar(i) = Selection.Range i = i + 1 Call Selection.Collapse(Direction:=wdCollapseEnd) Call Selection.Find.Execute Loop
Do ~ Loop
を用いて、マーカ部分をRange
オブジェクトとして拾い集めていく。
Find
オブジェクトのFound
プロパティがTrue
である場合、つまり、Find.Execute
メソッドの結果、次のマーカ部分がヒットした場合にはブロック内に進むことになる。
ループ内部に入ると、まずReDim Preserve
で配列の要素数を改定する。
Preserve
を忘れると、非常にマヌケなことになるので注意。
Set ar(i) = Selection.Range
でヒットして選択されているRange
オブジェクトを配列に格納する。
次にループ内部に突入した場合に備えてi
をインクリメントさせておいて、
Call Selection.Collapse(Direction:=wdCollapseEnd)
Selection.Collapse
メソッドを使って複数選択状態になっているカーソルを文字のカンチャンに移動する。引数Direction
がwdCollapseEnd
なので、選択されていた箇所の一番末尾にカーソルが移動する。
んで、最後に
Call Selection.Find.Execute
再度Find.Execute
メソッドを実行。
これで新たにマーカ部分がヒットしたら、再度ブロック内に突入するし、すでにヒットする部分がなければループを抜けることになる。
ループを抜けたら、全てのマーカ部分が配列にぶち込まれたことになるから、(8)からの2行
Call targetRange.Select getHighLightedRange = ar
で、もとあった位置にカーソルを戻し、配列をreturnしておしまい。
使ってみる
次のコードで使ってみる。
リスト2 標準モジュール
Public Sub testGetHighLightedRange() Dim Doc As Document Set Doc = ActiveDocument Dim highLightedRange() As Range highLightedRange = getHighLightedRange(Doc) Dim i As Long For i = LBound(highLightedRange) To UBound(highLightedRange) Debug.Print highLightedRange(i).Text Next End Sub
リスト1のgetHighLightedRange
の返り値として取得したRange
配列をFor
ループで回して、それぞれのText
プロパティの値をイミディエイト・ウインドウに、表示させる。
例によって、
このような文書を用意して実行してみる。
この通り、マーカ部分の文字列が表示された。
マーカ部分をRange
オブジェクトで取得できた証拠。
おわりに
これで、マーカのOn/Offが切り替え可能になった。