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を加算して返すようにしました。
これで良いのかどうか、引き続き検証します……。