Rangeオブジェクトの終端があるParagraphオブジェクトのインデックス番号を返すFunction(Word)
Rangeオブジェクトの終端があるParagraphオブジェクトのインデックス番号を返すFunction
更新頻度ガタ落ちですが、またしてもWordVBAネタです。
まずはコードを
お急ぎの方は、コードをコピッペして使ってください。
リスト1
Public Function getParagraphIndex( _ ByVal tgtRange As Range) As Long Dim ret As Long tgtRange.Start = 0 ret = tgtRange.Paragraphs.Count getParagraphIndex = ret End Function
たったこんだけ。正味2行w
まさかこんなに簡単にできるとは思っていませんでした。
使ってみる
たとえば、テキトーなドキュメントを用意して、
こんなふうにテキトーに範囲を選択しておく。
画像では、4~5段落にまたがった範囲を選択している。
で、イミディエイト・ウィンドウに次のコードを書いて[Enter]を押す。
?getParagraphIndex(Selection.Range)
すると、
ちゃんと「5
」が出力されておる。
バッチリ!
解説
こんなしょうもないコードだが、二つも発見があった。
短いコードなので再掲する。
リスト1(再掲)
Public Function getParagraphIndex( _ ByVal tgtRange As Range) As Long Dim ret As Long tgtRange.Start = 0 '……(1)' ret = tgtRange.Paragraphs.Count '……(2)' getParagraphIndex = ret End Function
Start(End)プロパティはRead/Writeだった
これは、完全に思い込み。
勝手にRead onlyだと固く信じて疑っていなかった。
Microsoft Docsの「Range.Start Property
」の項にも、
Range.Start property (Word)
Returns or sets the starting character position of a range. Read/write Long.
と明記してあるし。
(1)の
tgtRange.Start = 0
によって、tgtRange
が指し示すRange
オブジェクトの始端をドキュメントの先頭にしているわけだ。
RangeオブジェクトにもParagraphsコレクションがある
これも全然知らなかった。
「Paragraphs
」というぐらいだからてっきりDocument
オブジェクトの直参だと思っていた。
これまた、Microsoft Docsの「Range.Paragraphs Property
」の項にはっきりと
Range.Paragraphs property (Word)
Returns a Paragraphs collection that represents all the paragraphs in the specified range. Read-only.
と書いてある。
つまり、(1)を実行した段階で、tgtRange
が指し示すRange
オブジェクトの範囲は、〈ドキュメントの始端~選択範囲の終端〉になっているわけなので、(2)の
ret = tgtRange.Paragraphs.Count
によって、〈ドキュメントの始端~選択範囲の終端〉に含まれる段落数、すなわち選択範囲の終端がある段落が先頭から数えて何番目か、を表す数値が変数ret
に返る、というわけだ。
最初にこのアイディアを考えついたやつは天才だと思う。
おわりに
世の中、天才だらけでいやになるぜ。
追記(2022/02/18)
実は、ここで示したコードには重大なバグがあります。
なんと、段落の先頭にカーソルを置いて、引数tgtRange
にSelection.Range
を渡すと、一つ前の段落のインデックスを返してしまうのです。
取り急ぎ、応急処置をしたものを次に挙げておきます。
Public Function GetParagraphIndex( _ ByVal a_Target As Range) As Long Dim ret As Long Dim rng As Range Set rng = a_Target rng.Start = 0 ret = rng.Paragraphs.Count Dim pos As Long pos = rng.End If pos = 0 Then GoTo ReturnValue Dim char As String char = rng.Parent.Range(pos - 1, pos).Text If char = Chr(13) Then ret = ret + 1 End If ReturnValue: GetParagraphIndex = ret End Function
この記事を書いた当時から、コーディングスタイルが変わったので、ちょっと書きぶりは違いますが。
一応、引数a_Target
で渡されたRange
オブジェクトのStart
プロパティを0
にしたときに、Range
オブジェクトの終端が改段落だったら1
を加算して返すようにしました。
これで良いのかどうか、引き続き検証します……。