読者です 読者をやめる 読者になる 読者になる

Wordの表の各セルの文字列を利用しやすくする

Wordの表の中の文字列を取得するクラス

WordTableOperatorクラス

クラスモジュールを挿入して、オブジェクト名を「WordTableOperator」にした。

とりあえず、次のようなコードを書いた。

リスト1
Option Explicit
'フィールド'
Private wordApp_ As Word.Application
Private wordDoc_ As Word.Document
Private wordTable_() As Word.Table
Private isReady_ As Boolean
'アクセサ'
Public Property Get wordApp() As Word.Application
  Set wordApp = wordApp_
End Property
Public Property Get wordDoc() As Word.Document
  Set wordDoc = wordDoc_
End Property
Public Property Get wordTable(ByVal i As Integer) As Word.Table   '……(1)'
  Set wordTable = wordTable_(i) 
End Property
Public Property Get isReady() As Boolean
  isReady = isReady_
End Property
'コンストラクタ'
Private Sub Class_Initialize()
On Error GoTo ErrorCatch
  Set wordApp_ = GetObject(, "Word.Application")    '……(2)'
  Set wordDoc_ = wordApp_.ActiveDocument    '……(3)'
  Dim i As Integer
  ReDim wordTable_(wordDoc_.Tables.Count)    '……(4)'
  For i = 1 To UBound(wordTable_)    '……(5)'
    Set wordTable_(i) = wordDoc_.Tables(i)
  Next
  isReady_ = True    '……(6)'
  Exit Sub
ErrorCatch:    '……(7)'
  isReady_ = False
End Sub
'メソッド'
Public Function getTextFromCell(ByVal tableNum As Integer, _
                        ByVal rowNum As Integer, _
                        ByVal colNum As Integer) As String    '……(8)'
On Error GoTo ErrorCatch
  Dim str As String
  str = wordTable_(tableNum).Cell(rowNum, colNum).Range.Text    '……(9)'
  getTextFromCell = str    '……(*)'
  Exit Function
ErrorCatch:
  getTextFromCell = ""    '……(10)'
End Function

少し長くなった。ちょっと説明をば。

アクセサのところの(1)、

Public Property Get wordTable(ByVal i As Integer) As Word.Table
  Set wordTable = wordTable_(i) 
End Property

については、

akashi-keirin.hatenablog.com

コチラを参照。プロパティを配列にしている。

この場合は、Wordドキュメント内にある表を、配列として保持するようにしている。

さて、今回は珍しくコンストラクタを使う。

WordTableOperatorクラスのインスタンスが生成される時点でアクティブになっているWordアプリケーション及びドキュメントをセットしてしまうことにする。

まず、(2)の

Set wordApp_ = GetObject(, "Word.Application")

では、Wordアプリケーションのインスタンスを変数にセットするのに、GetObject関数を用いている。

akashi-keirin.hatenablog.com

このときにも使った方法だが、既に開いているWordアプリケーションを取得するため、このやり方にしている。

(3)の

Set wordDoc_ = wordApp_.ActiveDocument

で、現在アクティブになっているWordドキュメントを変数にセット。

この段階で、Wordドキュメント内にいくつの表があるかは判明しているので、(4)の

ReDim wordTable_(wordDoc_.Tables.Count)

で、配列用の変数wordTable_()を表の数でReDimしている。

(5)からの3行、

For i = 1 To UBound(wordTable_)    '……(5)'
  Set wordTable_(i) = wordDoc_.Tables(i)
Next

では、Wordドキュメント上の表を、配列wordTable_()に格納している。

Wordドキュメント上の表は、DocumentオブジェクトのTablesコレクションで取得できるので、Tablesコレクションのインデックスに1から順に数字を入れていけばそれぞれのTableオブジェクトが取得できる、という仕掛けだ。

続いて(6)。ここまでたどり着いたということは、エラーが出ていないということになるので、ここで

isReady_ = True

としてisReadyプロパティをTrueにしてやる。isReadyがTrueだということは、表が取得できているということなので、メインのコードで条件分岐に使うことができる。

なお、ここまでの過程でエラーが出ていたら、(7)の

ErrorCatch:
  isReady_ = False

に飛んでくるので、isReadyプロパティをFalseにして終了。

あとはメソッド。とりあえず1つだけにしている。

どうでもいいけど、「getTextFromCell」って、PANTERAの"Cowboys From Hell"みたいだな、オイw

(8)の

Public Function getTextFromCell(ByVal tableNum As Integer, _
                        ByVal rowNum As Integer, _
                        ByVal colNum As Integer) As String

を見たら分かるように、

  • 第1引数:表の番号
  • 第2引数:表内の行番号
  • 第3引数:表内の列番号



の3つを渡すと、セル内の文字列を返す、という形にしている。

(9)の

str = wordTable_(tableNum).Cell(rowNum, colNum).Range.Text

で指定したセルから文字列を取得。

なお、途中でエラーが出たら、(10)の

getTextFromCell = ""

で""を返すようにした。

動作確認

標準モジュールに次のコードを書いて、動作確認した。

スト2
Public Sub testWordTable01()
  Dim wtOperator As WordTableOperator
  Set wtOperator = New WordTableOperator
  Dim str As String
  If wtOperator.isReady = True Then
    str = wtOperator.getTextFromCell(1, 2, 2)    '……(1)'
    Debug.Print "表1の2行2列目セル内の文字列は、" & _
                Len(str) & "字ですわ。"
    Debug.Print "右端の文字のAsciiコードは、" & _
                getAsciiCodeOfChar(Right(str, 1)) & "番でんねん。"    '……(2)'
    Debug.Print "右端から2番目の文字のAsciiコードは、" & _
                getAsciiCodeOfChar(Mid(Right(str, 2), 1, 1)) & "番だすな。"    '……(3)'
  End If
  Set wtOperator = Nothing
End Sub
Private Function getAsciiCodeOfChar(ByVal objStr As String) As Integer
  Dim i As Integer
  For i = 0 To 255
    If Chr(i) = objStr Then
      getAsciiCodeOfChar = i
      Exit Function
    End If
  Next
  getAsciiCodeOfChar = 266
End Function

(1)の、

str = wtOperator.getTextFromCell(1, 2, 2)

では、getTextFromCellメソッドに引数(1, 2, 2)を渡しているので、

1番目の表の2行2列目のセルに入っている文字列を寄こせや!

ということになる。んで、得られた文字列を変数strにセットしている。

ちなみに、

1番目の表の2行2列目のセルに入っている文字列

ってのは、見かけ上は

f:id:akashi_keirin:20170505223742j:plain

「吉岡 稔真」です。

(2)の

getAsciiCodeOfChar(Right(str, 1))

では、getAsciiCodeOfCharメソッドに、(1)で得られた文字列(str)の右端の文字の文字コード番号を取得している。

これはまあ、Right関数だけだから簡単。

(3)の

getAsciiCodeOfChar(Mid(Right(str, 2), 1, 1))

がちょっとややこしい。

まず、

Right(str, 2)

で右端の2文字を抜き出して、その2文字に対してMid関数を使うことで、

右端の2文字の1文字目

すなわち、

右端から2文字目

を取得している。

まあ、

Mid(str, Len(str) - 1, 1)

でもいいですね。ハイ。

実行結果

f:id:akashi_keirin:20170505223754j:plain

こうなった。

指定のセル内の文字列は、見かけ上は「吉岡 稔真」の5文字(全角スペース含む)のはずだが、7文字となっている。

6文字目の文字コードが「7」、7文字目の文字コードは「13」となっている。

再びコチラによると、

f:id:akashi_keirin:20170505223812j:plain

ということなので、

Wordのセル内の文字列の末尾には、「ハナクソ」と「改行文字」がくっついている

ということらしい。

最後に

ということは、リスト1の(*)のところを

str = Left(str, Len(str) - 2)

とするだけで良いということになるなあ。

あとは、このクラスの使い勝手をいかに上げるか、だな。

@akashi_keirin on Twitter