最近は、rangeオブジェクトを使うようにしています。
rangeオブジェクトの利点を少しずつ理解してきました。
先週紹介したマクロでは、selectionを使わなかったために、選択した範囲をmySuperRangeとmyRangeとの二つの変数に保持することができました。
意図的にプログラムを書いたわけではなくて、知らずに使っていた結果として、上記のような機能をうまく使っていました。
通常、selectionを使うときには、「選択される文字列はカーソルの動きに影響される」と理解するとイメージしやすくなると思います。
例えば、「2009年4月18日」という文字列が文中に示されていて、「2009年」を選択したあとに、カーソルを別の場所に移動させると、「2009年」の選択は解除されます。
selectionオブジェクトで文字列を選択すると、同様のことがおこります。
つまり、選択範囲は常にカーソルと連動しますので、次の文字列を選択すると、前回選択したものは保持されません。
さて、今日は、上記のようなselectionでの検索とrangeでの検索の違いを少し体験できるプログラムを書いてみました。
まだ、学んでいる途中ですので理解不足もありますが、ひとまず自分が理解している範囲で説明したいと思います。
●プログラム概要
同じ動作をするマクロを4つの表現で書いてみました。
<作用>
「任意の全角数字一桁以上の文字列」+「年」の組み合わせを検索して、検索結果を表示させます。
例文として「2009年4月18日」と文章中に書いてください。
プログラムを実行すると、検索結果として「2009年」とメッセージボックスに表示されます。
<プログラム種類>
プログラム1:マクロの記録をもとにselectionを用いて書いたもの
プログラム2:プログラム1をrangeで書き換えたもの
プログラム3:プログラム2を簡潔に書き直したもの
プログラム4:プログラム3を別表現に書き直したもの
●プログラム1
Sub selection_test_1()
10 Selection.Find.ClearFormatting
20 With Selection.Find
30 .Text = "([0-9]{1,})年"
40 .Replacement.Text = ""
50 .Forward = True
60 .Wrap = wdFindContinue
70 .Format = False
80 .MatchCase = False
90 .MatchWholeWord = False
100 .MatchByte = False
110 .MatchAllWordForms = False
120 .MatchSoundsLike = False
130 .MatchFuzzy = False
140 .MatchWildcards = True
150 End With
160 Selection.Find.Execute
170 MSGBOX Selection
End Sub
10~160行で、検索して、170行で結果表示をしています。
検索するコードは、マクロの記録機能を使いました。
これを、rangeオブジェクトに書き換えます。
書き換えるコツは、こちらのページの5件目のコメントをご覧ください。
●プログラム2
Sub selection_test_2()
Dim myRange As Range
10 Set myRange = Selection.Range
20 With myRange.Find
30 .Text = "([0-9]{1,})年"
40 .Replacement.Text = ""
50 .Forward = True
60 .Wrap = wdFindContinue
70 .Format = False
80 .MatchCase = False
90 .MatchWholeWord = False
100 .MatchByte = False
110 .MatchAllWordForms = False
120 .MatchSoundsLike = False
130 .MatchFuzzy = False
140 .MatchWildcards = True
150 End With
160 myRange.Find.Execute
170 MSGBOX myRange
180 Set myRange = Nothing
End Sub
とりあえず、rangeオブジェクトに書き換えました。
単純に、selectionをselection.rangeとしただけです。
また、rangeで検索する場合には、検索窓の設定と連動しないこともメリットのひとつです。
通常、selectionでマクロを書くと、マクロで使った検索文字列や書式の設定が、手動で検索をする場合の「検索と置換」画面の設定に反映されてしまいます。
または、前回手動で「検索と置換」画面で設定した検索条件が、マクロを実行するときに反映されてしまいます。
よって、selectionでマクロを書く場合には、前回の検索と置換の条件を一旦初期化(クリア)する必要があるわけです。
しかし、rangeオブジェクトの場合には、「検索と置換」のフォーマットの初期化の必要がありません。
よって、1番目のプログラムの10行目のに記載されている「検索フォーマットの初期化」のコード
10 Selection.Find.ClearFormatting
を削除しました。
実行すると分かりますが、カーソルは移動せず、かつ、見つけた文字列を選択していないのですが、検索結果が表示されます。
(文書中に対応する文字列がない場合には、メッセージボックスは空欄になります)
180行のmyRangeを解除する方法は、他のプログラムを見たら書いてあったので、自分もそれをまねしています。
●プログラム3
Sub selection_test_3()
Dim myRange As Range
10 Set myRange = Selection.Range
20 With myRange.Find
30 .Text = "([0-9]{1,})年"
40 .Forward = True
50 .Wrap = wdFindContinue
60 .MatchWildcards = True
70 End With
80 myRange.Find.Execute
90 MSGBOX myRange
100 Set myRange = Nothing
End Sub
必要と思われる要素だけに削りました。
selectionの場合にも、マクロの記録で作成したコードから、必要なものだけを記載してプログラムをスリム化することができます。
この場合のスリム化の方法は別の機会に書きます。今回は、rangeのスリム化だけ説明します。
rangeでのスリム化のポイントは、今回はワイルドカード検索なので、その旨を指示しています(60行)。
あと、全文検索にして(50行)、カーソルの移動方向を下向き(40行)にしています。
●プログラム4
Sub selection_test_4()
Dim myRange As Range
10 Set myRange = Selection.Range
20 With myRange.Find
30 .Execute _
findtext:="([0-9]{1,})年", _
MatchWildcards:=True, _
Wrap:=wdFindContinue, _
Forward:=True
40 End With
50 MSGBOX myRange
60 Set myRange = Nothing
End Sub
書き方の参考例です。
プログラム3の20行から70行の内容を、プログラム4では、20行から40行にまとめてあります。
同じ検索の条件を別の書き方にする一例です。
「Microsoft Visual Basicのヘルプ」(VBEでF1ボタンを押すと表示)やニューズグループの例文を見て学びました。
自然言語(英語や日本語)には、同じ意味を伝える文章であっても、わかりやすいものとわかりにくいものがあります。
プログラム言語にもわかりやすい、わかりにくい、があると思います。
当然、読み手の知識量にもよりますが。。。まだ私には読めないプログラム文がたくさんあります。
今回の例ではわかりやすさはあまりかわらないかもしれませんが、冗長か簡潔かという点での違いでしょうか。
あと、書く際に、手間が省けますね。
プログラムが複雑になると処理速度にもかかわることみたいですが、上記の程度であれば、気にする必要はないですね。
最近のコメント