初めてのIE操作(3)~HTMLソースをファイルに出力するメソッド
WebページのHTMLソースを出力するメソッド
前々回、
前回
の続き。
Webページ/アプリを操作するには、HTMLがどうなっているのかを知らなければどうにもならない。
ただし、前回すでに起動中のIEオブジェクトを捕まえて、Document
オブジェクトを取得するところまで行っているので、楽勝である。
targetIE.Document.all(0).outerHTML
たったこれだけ。
さすがにこれだけだと面白くないので、取得したHTMLソース文字列をファイルに出力できるようにした。
コード
リスト1 標準モジュール
Private Sub appendTextToFile(ByVal fileFullName As String, _ ByVal targetText As String) Dim n As Long n = FreeFile(0) Open fileFullName For Append As n Print #n, targetText Close #n End Sub
コイツを利用して、取得したHTMLソースをファイルとして保存するようなFunction
を作る。
リスト2 標準モジュール
Public Sub createHTMLSource(ByVal targetIE As InternetExplorer, _ ByVal sourceName As String) Call appendTextToFile( _ ThisWorkbook.Path & "\" & sourceName & "_src.html", _ " targetIE.Document.all(0).outerHTML) Set targetIE = Nothing End Sub
Document.all(0).outerHTML
で取得した文字列をappendTextToFile
メソッドに渡して、ThisWorkbook
と同じディレクトリにファイルを出力するメソッド。
出力場所まで指定したければ引数を増やせば良い。
使ってみる
次のコードで実験。
リスト3 標準モジュール
Public Sub test() Dim targetIE As New InternetExplorer With targetIE .Visible = True Call .Navigate("http://akashi-keirin.hatenablog.com/entry/2018/12/16/001606") Do While .Busy Or _ .readyState <> READYSTATE_COMPLETE DoEvents Loop End With Set targetIE = getIEByTitle("素人が") Call createHTMLSource(targetIE, "akashi_keirin") End Sub
例によって、テキトーにブレークポイントを設置して、手動待機(w)しながら実行してみる。
実行結果
実行してみると、ThisWorkbook
のディレクトリに、
この通りakashi_keirin_src.html
というファイルができている。
エディタで開いてみると、
一瞬ぎょっとするような画像だが、よく見ると確かにHTMLソースである。
ここまで来たらリーチがかかったようなもん。オープンリーチかも知れんけど。
HTMLの要素を解析して、操作対象を特定して操作するだけ。それは次回。
参考
初めてのIE操作(2)~起動中のIEを取得するFunction
ウインドウのタイトルを元に起動中のIEを取得するFunction
前回
の続き。
ページのURLや、HTMLソースが分からないときがある。
Webアプリで移動した先のページなんかの場合だ。たいていアドレスバーが切られていたりするし、右クリックしても、ショートカットキー([Ctrl]+[U]
)を押してもソースが表示されない。
そんな場合にどうするか。
ウインドウが開いているのだから、それを頼りにIEオブジェクトを取得し、そのHTMLドキュメントオブジェクトから取得すれば良い。
そのためには、まず起動中のIEを取得する必要がある。
この件についてはコチラのページを大いに参考にさせていただいた。
既に開かれているInternetExplorerを取得する(起動済みIEオブジェクトの取得)
開いているウインドウを片っ端から調べ、それが「Internet Explorer」であり、かつウインドウのタイトルが一致していればオブジェクトとして取得する、というやり方。
コード
前回のMicrosoft HTML Object Library
、Microsoft Internet Controls
に加え、Microsoft Shell Controls And Automation
とMicrosoft Scripting Runtime
にチェックを入れている。
リスト1 標準モジュール
Public Function getIEByTitle( _ ByVal targetTitleKey As String) As InternetExplorer Dim ieApp As New InternetExplorer Dim shellApp As New Shell Dim shellWin As Object For Each shellWin In shellApp.Windows '……(1)' If shellWin.Name = "Internet Explorer" Then '……(2)' On Error Resume Next '……(3)' If InStr(1, shellWin.Document.Title, targetTitleKey) > 0 Then '……(4)' If Err.Number = 0 Then '……(5)' Set ieApp = shellWin Exit For End If End If On Error GoTo 0 '……(6)' End If Next If ieApp Is Nothing Then Exit Function Set getIEByTitle = ieApp '……(7)' End Function
Shell
オブジェクトを使って、Windowsの「エクスプローラー」にアクセスする、というやり方。
(1)の
For Each shellWin In shellApp.Windows
で、Windowsの「エクスプローラー」に当たるものをしらみつぶしにする。
変数shellWin
に入るのはInternetExplorer
型のオブジェクトとは限らない(通常の「エクスプローラー」(フォルダを開いた時のアレ)の場合がある)ので、Object
型にしている。
ここからFor
ループ内部。
まず(2)の
If shellWin.Name = "Internet Explorer" Then
で、変数shellWin
内のオブジェクトのName
プロパティの文字列を調べる。
オブジェクトの正体がIEオブジェクトなら、「Internet Exprorer
」が返る。通常のエクスプローラーオブジェクトなら、「エクスプローラー」が返る。
「Internet Explorer」以外の値が返っているならさっさと次へ行く。「Internet Explorer」が返っているなら第一関門突破。Then
以下へ進む。
(3)で
On Error Resume Next
として、エラーが出ても無視して次へ進むようにしている。これは、(4)の
If InStr(1, shellWin.Document.Title, targetTitleKey) > 0 Then
を評価する際に、変数shellWin
オブジェクトにDocument
プロパティがなかったりするとエラーになってしまうため。
エラーが出たからといってここで止まってしまっては、求めているShellのウインドウにたどり着けない。
本題に戻る。(4)の
If InStr(1, shellWin.Document.Title, targetTitleKey) > 0 Then
では、変数shellWin
に入っているオブジェクトからDocument
オブジェクトを取得、そのTitle
プロパティの文字列に、引数で渡したtargetTitleKey
の文字が含まれているかどうかを調べている。
含まれていれば、InStr
関数が1
以上の整数を返すので、Then
以下に進む。
(5)からの4行
If Err.Number = 0 Then Set ieApp = shellWin Exit For End If
では、エラーが出ていないか調べて、大丈夫だったら現在のshellWin
を返り値用の変数ieApp
にセットしてFor
ループから脱する。
今にして思えば、エラーの状態を調べるというのは不要かも知れない……。
ちなみに、次のループに進む前に(6)の
On Error GoTo 0
エラーをリセットしておく。
最後に(7)の
Set getIEByTitle = ieApp
で捕まえたIEオブジェクトをreturnしておしまい。
使ってみる
次のコードで実行。
リスト2 標準モジュール
Public Sub test() Dim targetIE As New InternetExplorer With targetIE .Visible = True Call .Navigate("http://akashi-keirin.hatenablog.com/entry/2018/12/16/001606") Do While .Busy Or _ .readyState <> READYSTATE_COMPLETE DoEvents Loop End With Set targetIE = getIEByTitle("素人が") '……※' Debug.Print targetIE.Document.Title '……※' Debug.Print targetIE.Document.locationURL End Sub
リスト1のgetIEByTitle
メソッドにキーワード「"素人が"」を渡して、起動中のIEオブジェクトを捕まえ、そのDocument
オブジェクトのTitle
プロパティとlocationURL
プロパティの値をイミディエイト・ウインドウに表示させるコード。
ちなみに、実行時は、ステップ実行で読み込み待ちの時間を調整した。
ページを読み込んで準備完了になるまでに次のコードを実行したりするとエラーになるので、本来はいろいろチューニングしないといけないんだけれど、めんどくさいので省略。
実行結果
上記コード中の※のところにブレークポイントを設定して、十分に待ち時間を取って実行した。
このとおり、ウインドウのタイトルと、ページのURLが表示されている。
WebアプリのページURLが分からないときは、この方法で取得が可能。
実は、ページのHTMLソースも、この時点で取得できたも同然だったりする。
そのあたりは次回。
参考
初めてのIE操作(1)
初めてのIE操作(1)
IEベースの業務用Webアプリの操作がくっそダルかったので、生まれて初めてVBAからのIE操作にチャレンジしてみたら、意外と簡単だったので、報告。
業務用Webアプリ操作のために私が乗り越えなければならなかった壁は以下の通り。
この後、入力・確認したデータをサーバに送信するためにボタンをクリックしないといけないが、さすがにそこまで自動にするのは怖いのでとりあえず以上の4点。
厄介だったのが、ページのソースが通常の方法では表示されなかったこと。
その辺は、本編で追々……。
Webアプリ操作のために必要なこと
先にまとめておく。
まず、操作したいWebアプリのページのHTMLを取得することが必要。
次に、取得したHTMLソースを解析して、どの要素にどのような操作をすれば良いかを探る。
基本的にこれだけできたら良いだけなので、思っていたより簡単だった。
IEを起動してページを表示する
これは簡単。
基本的に、InternetExplorerオブジェクト(以下「IEオブジェクト」と言う。)を取得しさえすれば、あとはIEオブジェクトのNavigate
メソッドを実行するだけ。
コードは、
Dim targetIE As New InternetExplorer Call targetIE.Navigate("サイトのURL")
とするだけ。
WebアプリのページURLが分かるならこれだけでページを呼び出すことはできる。
URLが分からない場合は、ちょっとややこしいやり方が必要になる。
HTMLソースが通常の方法で表示されない場合と同じ苦労がいる。言い方を変えれば、HTMLソース問題さえ解決すれば、同時に解決するということ。たいした問題ではない。
実験
その前に、参照設定をしておくと便利。
このように、Microsoft HTML Object Library
とMicrosoft Internet Controls
にチェックを入れておく。
リスト1 標準モジュール
Public Sub test() Dim targetIE As New InternetExplorer With targetIE .Visible = True Call .Navigate("http://akashi-keirin.hatenablog.com/entry/2018/12/16/001606") End With End Sub
Visible
プロパティをTrue
にしているので、起動したIEは画面表示される。
Navigate
メソッドの引数には拙ブログの前回記事のURLを渡した。
コイツを実行すると、
ほれ、この通りIEで目標のページが表示された。
この後、開いたページにあれこれやっていくわけだが、それはまた次回。
参考
マーカ部分を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が切り替え可能になった。
UndoRecordオブジェクトというものがある(Word)
UndoRecordオブジェクトというものがある
前回の
に、id:imihito さんからコメントをいただいた。
曰く、
また、Undoの履歴は、以下のようにするとひとまとめに出来たはずです
```vb Application.UndoRecord.StartCustomRecord '処理 Application.UndoRecord.EndCustomRecord ```
と。
な、なんだってー!(MMR風)
さっそくやってみた。
UndoRecordオブジェクトを使う
例によって公式のUndoRecordオブジェクトの項を見ると、
UndoRecord オブジェクト (Word)
元に戻すスタックにエントリ ポイントを提供します。
注釈
作成し、Word の [元に戻すスタックにユーザー定義の undo レコードを変更するには、 UndoRecordオブジェクトを使用します。
例
次のコード例は、 UndoRecordオブジェクトをインスタンス化します。
VB
Dim objUndo As UndoRecord Set objUndo = Application.UndoRecord
だそうである。機械的な飜訳だからか、異様に読みづらい。
英語版で見てみよう。
UndoRecord object (Word)
Provides an entry point into the undo stack.
Remarks
Use the UndoRecord object to create and modify custom undo records in the Word undo stack.
Example
The following code example instantiates an UndoRecord object.
VB
Dim objUndo As UndoRecord Set objUndo = Application.UndoRecord
Wordのアンドゥ情報を積んでおく場所への入り口を提供する、みたいな感じ?
メソッドやプロパティへのリンクが記事中にないので、サイドバーみたいなところから、Methods
→StartCustomRecord
へと辿っていく。すると、
UndoRecord.StartCustomRecord method (Word)
Initiates the creation of a custom undo record.
Syntax
expression.
expression A variable that represents an 'UndoRecord' object.
Parameters
Name Repuired/Optional Data type Description Name Optional String Specifies the name of the custom undo record. This string is limited to 64 characters. If a longer string is supplied, the string is truncated to 64 characters. 注意
If this parameter is omitted or is an empty string, Word uses the name of the first command executed as the name of the undo record.
Remarks
StartCustomRecord begins the creation of a custom undo record, which records all actions done to the application while it is active under a record defined by Name .
Example
VB
Sub TestUndo() Dim objUndo As UndoRecord Set objUndo = Application.UndoRecord objUndo.StartCustomRecord ("My Custom Undo") 'Add some actions here objUndo.EndCustomRecord End Sub
UndoRecord
オブジェクトを作成して、そのStartCustomRecord
メソッドとEndCustomRecord
メソッドを、アンドゥの対象とする処理の前後で実行すれば良いようだ。
使ってみる
前回のリスト1を少し改変する。
リスト1 標準モジュール
Public Sub test() Dim winAPI As New WindowsAPI Dim startTime As Long startTime = winAPI.getNowTickCount Dim Doc As Document Set Doc = ThisDocument Dim targetChar As Range Dim tmpUndo As UndoRecord '……(1)' Set tmpUndo = Doc.Parent.UndoRecord Call tmpUndo.StartCustomRecord("TempUndo") For Each targetChar In Doc.Characters With targetChar If .HighlightColorIndex = wdYellow Then .HighlightColorIndex = wdNoHighlight End If End With Next Call tmpUndo.EndCustomRecord '……(2)' Dim endTime As Single endTime = (winAPI.getNowTickCount - startTime) / 1000 Call MsgBox("処理時間:" & endTime & vbCrLf & _ "文字数 :" & Doc.Characters.Count) End Sub
前回から変わったのは、(1)、(2)のところ。
(1)からの3行
Dim tmpUndo As UndoRecord Set tmpUndo = Doc.Parent.UndoRecord Call tmpUndo.StartCustomRecord("TempUndo")
では、変数tmpUndo
にUndoRecord
オブジェクトをぶち込んで、StartCustomRecord
メソッドを実行。
メインの処理の記述の後、(2)の
Call tmpUndo.EndCustomRecord
でEndCustomRecord
メソッドを実行する。
これで、コード実行後、アンドゥで元に戻せることになる。
やってみる
ひとまず、この状態でリスト1を実行。
こうなる。
んで、「元に戻す」アイコンにマウスカーソルを当てると、
「元に戻す TempUndo」と表示されている。
なるほど、StartCustomRecord
メソッドの引数は、こんなところに生きるのか。
「元に戻す」アイコンをクリックすると、
おおっ! マーカが復活した!
おわりに
控え目に言っても、これは超便利ではなかろうか。
id:imihito さん、本当にありがとうございました!
Document.Charactersコレクションの要素を一つづつ処理するのは大変(Word)
WordでDocument.Charactersオブジェクトを一つづつ処理するのは異様に時間がかかる
資料の修正箇所に網掛けをしたものと、同じ内容で網掛けのないバージョンを要求されることがある。
そして、網掛けありバージョンと網掛けなしバージョンが併立するということが起こる。
ここまではまあ良い。
ヒサンなのは次のようなケースだ。
- 資料に再修正の指示が出る。
- 再修正し、網掛けありバージョンと網掛けなしバージョンを作成する
- 再修正を繰り返すうちに、どこかで保存のタイミングを誤る
- 網掛けありバージョンと網掛けなしバージョンの内容にずれが生ずる
およそ、事務系の仕事をしていれば、誰でも経験するのではなかろうか。
VBAで網掛けを外す
……と、ここまで「網掛け」という用語を用いているが、実際にはHighLight
機能を使うことにする。「蛍光ペン」というやつだ。白黒印刷すれば、網掛けとほぼ同じ効果なので、ひとまずこれで代用する。
やり方としては、Document
オブジェクトのCharacters
コレクションの要素を一つづつ取り出して、HighLightIndex
プロパティがwdYellow
だったらwdNoHighLight
に変える、というだけのものとする。
リスト1 標準モジュール
Public Sub test() Dim winAPI As New WindowsAPI '……(1)' Dim startTime As Long startTime = winAPI.getNowTickCount Dim Doc As Document '……(2)' Set Doc = ThisDocument Dim targetChar As Range For Each targetChar In Doc.Characters '……(3)' With targetChar If .HighlightColorIndex = wdYellow Then '……(4)' .HighlightColorIndex = wdNoHighlight End If End With Next Dim endTime As Single '……(5)' endTime = (winAPI.getNowTickCount - startTime) / 1000 Call MsgBox("処理時間:" & endTime & vbCrLf & _ "文字数 :" & Doc.Characters.Count) End Sub
(1)からの3行
Dim winAPI As New WindowsAPI Dim startTime As Long startTime = winAPI.getNowTickCount
はお気になさらねえでくだせえ。
WinAPI
クラスというのは、割とよく使うWindowsAPI
の関数を、手軽に使えるように自作のクラスモジュールにまとめたもの。
ここでは、あの有名なGetTickCount
関数をラップしていると思ってください。
メインの処理は(2)からの10行
Dim Doc As Document Set Doc = ThisDocument Dim targetChar As Range For Each targetChar In Doc.Characters '……(3)' With targetChar If .HighlightColorIndex = wdYellow Then '……(4)' .HighlightColorIndex = wdNoHighlight End If End With Next
Document.Characters
コレクションの要素を一つづつ取り出して、HighlightColorIndex
プロパティの値によって処理を切り替えている。
Characters
コレクションの要素がCharacter
オブジェクトではなく、Range
オブジェクトだというあたりが注意かな。
中身も詳しく見ておく。(3)からの7行
For Each targetChar In Doc.Characters With targetChar If .HighlightColorIndex = wdYellow Then '……(4)' .HighlightColorIndex = wdNoHighlight End If End With Next
では、For Each ~ Next
を用いて、Characters
コレクションの要素一つ一つを処理する。
ループ内部では、(4)からの3行
If targetChar.HighlightColorIndex = wdYellow Then targetChar.HighlightColorIndex = wdNoHighlight End If
で、Characters
コレクションの要素であるRange
オブジェクト(変数targetChar
の中身)のHighlightColorIndex
プロパティの値を調べ、値がwdYellow
だったら、すなわち黄色マーカが施されていたら、HighlightColorIndex
プロパティの値をwdNoHighlight
に変える、すなわちマーカを除去する、という処理を行う。
残りの、(5)からの4行(実質3行)
Dim endTime As Single endTime = (winAPI.getNowTickCount - startTime) / 1000 Call MsgBox("処理時間:" & endTime & vbCrLf & _ "文字数 :" & Doc.Characters.Count)
は、(1)の続き。処理後の時間を取得して、処理に掛かった時間を表示するだけ。
実行
このようなWord文書を用意する。文書内には、ご覧のようにところどころ黄色マーカを施してあるw
この状態で、リスト1を実行してみる。ちなみに、画面左下の文字数カウントでは「1082
文字」と出ている。
なんと、3.785
秒もかかっている。しかも、なぜか文字数(正確にはDocument.Characters.Count
の値だけど)は1218
になっている。
おわりに
1000
字チョイなんて、コンピュータにとっては屁みたいな文字数だと思ったのだが、なぜこんなにヒマがかかるのだろうか。
しかも、今回のコードは単にマーカ部分をマーカなしにするだけであり、ひとたび実行すると、元の状態を復元することはできない(WordのVBAの場合、アンドゥでそこそこ戻れるけど。)。
マーカあり/なしを切り替えるには、マーカされている部分を記憶しておく必要がある。そのためには状態を取得するためにCharacters
オブジェクトの要素にアクセスする必要がある。
たぶん、やり方がマズいのだろうけど、何か良いやり方はないものか。
飛び地状態のセル範囲にも名前を付けることができる(Excel)
飛び地状態のセル範囲にも名前を付けることができる
Excel使いこなしマンには常識だったのかも知れないが、便利だなと思ったので記しておく。
飛び地状態のセル範囲に名前を付けてみる
まず、
こんな風に、投げやりに文字列を入れておく。
別に入れなくてもいいんだけど。
んで、[Ctrl]キーを押しながら、ポチポチと選択。
次に、イミディエイト・ウインドウに、
Selection.Name = "Dekosuke"
と打ち込んで、[Enter]。
すると、
画面上は何の変化もないけれど、
一旦選択状態を解除して、イミディエイト・ウインドウに、
Sheet1.Range("Dekosuke").Select
と打ち込んで、[Enter]。
この通り、飛び地状態のセル範囲がキッチリ選択される。
おわりに
長く使い続けるマクロで使用することはオススメできないが、サクッと書いて使い捨てにするマクロになら使える場面もあるかも知れない。
不規則なセル範囲に一括して処理を施したい場合なんかに使えそうです。Application.Union
メソッドを使うより、よっぽど楽です。