Word VBA 表(table)のアクティブなセルのアドレス、テーブル番号、ページ数を返す関数 UDF Finding Table #, cell address, page # And Section # From Activecell

Current row in VBA Word - Stack Overflow
https://stackoverflow.com/questions/8668311/current-row-in-vba-word

これを応用して、アクティブ（現在選択するか、カーソルがある）テーブルのCellからアドレスが返る関数を作ってみます

##R1C1形式とA1形式が必要
Wordは数式の場合はA1形式で、指定したセルにジャンプする場合など、数式以外ではR1C1形式を使います。
このため、列については2通り必要です。

##重要なお断り
###A1形式は26列まで
この関数は最大列を26行としています。それ以上は面倒ですし、そもそも26列ある表をWordで作りますでしょうか？

###ネスト、結合禁止
ネストはネストレベルが絡むので、うまく活きません。
また結合は、そこだけアドレスがずれます。
エクセルと同じく一番左上のアドレスを取ります。
通常はA、B、CとExcelのように割り当てられています。
どこにもそう書いていないのですが。
しかし、たとえばA、Bを結合すると、C列はB列になってしまいます。
単純に列数で割り当てられているみたいです。
ExcelhaA列とB列を結合してもC列はC列です。
また、現在カーソルはあるテーブルのあるセルにあるとします。

#コードとポイント
##ActiveなところはSelectionになる
もちろんActiveなんとかというのはありますが、ないときはSelectionのあとに続けることが多いみたいです。
##Selection.Cells(1)
セルを一つだけ選択するのでこう書きます。
ActiveCellというようなものはWordにはないようです。

##コード

###まずSubを作ります

```vb
Sub wdActiveCellInfo()
Debug.Print wdFnAcCelColA1Idx(Selection.Cells(1))
End Sub
```

ここでイミディエイトにアドレスを表示させるためにセルの情報を関数に振ります。
`Selection.Cells(1)`となっています。独特な表記です。

###行番号

```vb
Function wdFnAcCelRowIdx(c As Word.Cell) As Long
'For Word VBA 
'for Cell Of table
wdFnAcCelRowIdx = c.RowIndex
End Function
```

行番号は1行コードです
cはWordのCellオブジェクトです。
ExcelはRangeですが。

###列番号(C1形式）
単純にRowIndexを返すものです。

```vb
Function wdFnAcCelC1ColIdx(c As Word.Cell) As Long
'For Word VBA 
'for Cell Of table
wdFnAcCelC1ColIdx = c.ColumnIndex
End Function
```

1行コードです
cはWordのCellオブジェクトです。


###列番号（A1）形式
本当は26以上もやろうかと思いましたが、挫折しました。
元ネタはOffice田中大先生です。
つまり列番号に64を足して文字コードをずらして取得します。
いちおうZZまで取得できるかもしれませんが、676列なんてありえないでしょう

```vb
Function wdFnAcCelColA1Idx(c As Word.Cell) As String
'For Word VBA 
'for Cell Of table
Dim buf As String, cnt As Long
Dim lngC As Long
Dim lDig As Long
lngC = c.ColumnIndex
' lDig = Int(Log(lngC) / Log(10))
If lngC / 26 < 1 Then
buf = Chr(lngC + 64)
ElseIf lngC > 26 Then
idig = Int((lngC - 26) / 26)
buf = Chr(idig + 1 + 64) & Chr((lngC - ((Int((lngC - 26) / 26) + 1) * 26)) + 64)
End If
wdFnAcCelColA1Idx = buf
End Function
```

###テーブルの番号

https://wordribbon.tips.net/T010897_Index_Number_for_the_Active_Table.html
さすがAllenさんです。Subで作っている。
なんと仮のBookMarkを振って、それを探すというもの。
当方はFunctionでカレントのセルに仮のBookMarkを振り、探します。
まずCellsのParentはTableではなくDocumentでした。
そこでDocumentを取得します。
これでテーブル数はわかります。
そしてセルを選択してブックマークを振り、ブックマークが見つかったら削除します。
ただしブックマークを削除した状態ではセル全体が選択されているため意味が変わります。
最初からセルを選択していればこれでもいい場合もありますが。通常はそういう状態ではないでしょう。
なので選択状態を1文字移動させて解除します。
https://docs.microsoft.com/ja-jp/office/vba/api/word.table.descr
本当は悔しいのでテーブルの詳細を使いたかったのですが、なんとCellから上にたどるとテーブルが返ってこない。
ネストなどを考えているのでしょうけど。
なおDescr（詳細）はテンプレートやよく使う定型文書は番号では分かりづらいので設定した方がいいと思います。

```vb
Function wdFnAcTblNum(c As Word.Cell)
Dim wDoc As Word.Document
Dim wTbl As Word.Table, wTbls As Word.Tables
Dim i As Long
Set wDoc = c.Parent
Set wTbls = wDoc.Tables
c.Select
Selection.Bookmarks.Add ("tmpBm")
For i = 1 To wTbls.Count
Set wTbl = wTbls(i)
wTbl.Select
If Selection.Bookmarks.Exists("tmpBm") Then
wDoc.Bookmarks("tmpBm").Select
wDoc.Bookmarks("tmpBm").Delete
Selection.MoveLeft Unit:=wdCharacter, Count:=1, Extend:=wdExtend
Exit For
End If
Next i
wdFnAcTblNum = i
End Function
```

Reliefさんは上から行っています。うちは下からという感じですね。
https://www.relief.jp/docs/word-macro-select-table.html
Reliefさんはエラーチェックを入れています。
ただ、アルファベットで返す関数も作ってほしかった。まあどっかにあるとは思いますし、そもそも数式を入れる人が少ないからでしょう。
https://www.relief.jp/docs/word-vba-row-number-column-number-table.html

##Page数を返す関数
これはBookMarkを2つ使います。
Activeなページを選択するとカレントのカーソルが移動します。
そこで、一度ブックマークを振ってから、Pageを選択してPage数を取得し、
取得後、もとの位置に返します。
ただし、表はPageをまたがることがあるため、正確なページが返るかはわかりません。
編集する場合はあくまでTable番号です。
しかし、Tableは1ページから1番とは限りません。
また1ページめと2ページめに表がまたがっている場合、カレントのセルの位置が帰るため、必ずしも正確なページ数が返りません。
ただしブックマーク等で見てみると、次のページに属しているようです。
というのもブックマークでテーブルを選択すると、2ページになるためです。
それでも、およその目安としてページ番号がいるのではないかと思い、作ってみました。

```vb
Function wdFnAcTblPgNum(c As Word.Cell)
Dim wDoc As Word.Document
Dim wTbl As Word.Table, wTbls As Word.Tables
Dim i As Long
Dim iPage As Long
Dim wBM As Bookmark
Set wDoc = c.Parent
Set wTbls = wDoc.Tables
c.Select
Selection.Bookmarks.Add ("tmpBm") 'CellにBookMarkを振る
Selection.Bookmarks("\page").Select 'ActiveなページをBookMarkで取得
iPage = Selection.Information(wdActiveEndPageNumber) '今回は機械的に指定範囲を返す方を使用
For i = 1 To wTbls.Count ’Table番号ではなく、元の位置に帰るため、Tableを回す。
  Set wTbl = wTbls(i)
  wTbl.Select
  If Selection.Bookmarks.Exists("tmpBm") Then
    wDoc.Bookmarks("tmpBm").Select
    wDoc.Bookmarks("tmpBm").Delete
    Selection.MoveLeft Unit:=wdCharacter, Count:=1, Extend:=wdExtend
    Exit For
  End If
Next i
wdFnAcTblPgNum = iPage
End Function
```
##セクション番号

```vb
Function wdFnAcTblSecsNum(c As Word.Cell)
Dim wDoc As Word.Document
Dim wTbl As Word.Table, wTbls As Word.Tables
Dim i As Long
Dim iSecs As Long
Dim wBM As Bookmark
Set wDoc = c.Parent
Set wTbls = wDoc.Tables
c.Select
Selection.Bookmarks.Add ("tmpBm")
Selection.Bookmarks("\Section").Select
iSecs = Selection.Information(wdActiveEndSectionNumber)
For i = 1 To wTbls.Count
  Set wTbl = wTbls(i)
  wTbl.Select
  If Selection.Bookmarks.Exists("tmpBm") Then
    wDoc.Bookmarks("tmpBm").Select
    wDoc.Bookmarks("tmpBm").Delete
    Selection.MoveLeft Unit:=wdCharacter, Count:=1, Extend:=wdExtend
    Exit For
  End If
Next i
wdFnAcTblSecsNum = iSecs
End Function
```

Page数と全く同じ原理で、セクション番号も取得できます。
紙と異なってPage数よりは実はセクション番号の方が絶対的な区切りになります。
何ページあってもセクション1はセクション1なのです。
なのでページ数が多いときはセクションを区切ることが重要になります。


# 参考文献

https://www.relief.jp/docs/018015.html
Informationのリスト
テンキー情報ONなど、色々と使えます。
本当はReliefさんが言っているようにTableにあるかどうかを加えます。
https://docs.microsoft.com/ja-jp/office/vba/api/word.bookmark
BookMarkオブジェクトの解説
https://docs.microsoft.com/ja-jp/office/vba/word/concepts/miscellaneous/predefined-bookmarks
今回のキーになるのが定義済みのブックマーク
テーブル自体もブックマークがあるのですが、なぜかテーブルのプロパティにテーブル番号がないのです。
このため、考えられる方法はすべて、ドキュメントの総テーブル数の取得から回転することになります。

https://stackoverflow.com/questions/8668311/current-row-in-vba-word
WordでVBAを使う動機としては位置情報が多いと思います。そして使わなくなる動機は位置情報がさっぱり取得できないからです。
Page番号を取得するマクロ https://www.ka-net.org/blog/?p=8654
Page数のマクロも上でいいかどうかは保証できません。
というのも表がまたがる場合があるからです。
Wordの隠れた特徴はPageごとで区切るという概念が弱いことです。
通常、紙で印刷しているときと非常に異なっています。
これは目まぐるしくページ数が変化するためだと思われます。
単語、段落などPageをまたがるものが多いため、こうなっているものと思われます。
今回は機械的にPage数を出しています。

#効果
これによってテーブルの番号とセルの位置を完全に把握できます。
このため、フィールドコードを挿入するマクロを作っても、カレントのテーブル番号と位置が取得できるため、複数の表が作っていけることになります。Tables(1) に限定しなくてもいいわけです。
ただTable番号は作った順であり、1からたどっても上から下にいくとは限りません。
なのでページ番号やセクション番号を取得するものも作ってみました。