Wordの表の各セルの文字列を利用しやすくする(2)
クラスのプロパティに二次元配列を持たせてみる
表の内容をそのまま配列にする
「表」ということは、二次元配列と同じ形なんである。
そこで、
クラスのプロパティを二次元配列にする
ことを試みた。
クラスの改造
まず、前回記事のリスト1のうち、フィールド・アクセサ部分を以下のように書き換える。
リスト1-1
'フィールド' Private wordApp_ As Word.Application Private wordDoc_ As Word.Document Private wordTable_() As Word.Table Private tableArray_() As String '……(1)' Private maxRow_ As Integer '……(2)' Private maxColumn_ As Integer 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 Set wordTable = wordTable_(i) End Property Public Property Get tableArray(ByVal r As Integer, _ ByVal c As Integer) As String '……(3)' tableArray = tableArray_(r, c) End Property Public Property Get maxRow() As Integer maxRow = maxRow_ End Property Public Property Get maxColumn() As Integer maxColumn = maxColumn_ End Property Public Property Get isReady() As Boolean isReady = isReady_ End Property
(1)の
Private tableArray_() As String
では、新たにtableArray_()というString型の配列変数を準備。
さらに、(2)からの2行
Private maxRow_ As Integer Private maxColumn_ As Integer
でmaxRow_及びmaxColumn_という変数を準備した。この2つの変数には、取り扱うWordの表の行数と列数を格納する。
(3)の
Public Property Get tableArray(ByVal r As Integer, _ ByVal c As Integer) As String tableArray = tableArray_(r, c) End Property
は、tableArrayの値にアクセスするためのアクセサメソッド。
二次元の配列なので、引数が2つ必要。
そして、メソッドも1つ追加する。
リスト1-2
Public Sub createArrayFromTable(ByVal tableNum As Integer, _ ByVal hasHeader As Boolean) '……(1)' On Error GoTo ErrorCatch Dim startRow As Integer '……(2)' If hasHeader = True Then startRow = 2 If hasHeader = False Then startRow = 1 With wordTable_(tableNum) '……(3)' maxRow_ = .Rows.Count '……(4)' maxColumn_ = .Columns.Count ReDim tableArray_(maxRow_, maxColumn_) '……(5)' Dim iRow As Integer '……(6)' Dim iColumn As Integer Dim str As String Dim n As Integer n = 1 For iRow = startRow To maxRow_ '……(7)' For iColumn = 1 To maxColumn_ '……(8)' str = .Cell(iRow, iColumn).Range.Text '……(9)' tableArray_(n, iColumn) = Left(str, Len(str) - 2) '……(10)' Next n = n + 1 '……(11)' Next End With Exit Sub ErrorCatch: End Sub
まずは(1)の
Public Sub createArrayFromTable(ByVal tableNum As Integer, _ ByVal hasHeader As Boolean)
でお分かりの通り、2つの引数を受け取るようにしている。
- 第1引数:Wordドキュメント内の表の番号
- 第2引数:1行目がラベル行なのかどうか
の2つを受け取って実行する。
(2)からの3行、
Dim startRow As Integer If hasHeader = True Then startRow = 2 If hasHeader = False Then startRow = 1
では、引数hasHeaderの値によって変数startRowの値を切り替えている。
たとえば、hasHeaderがTrueであるということは、表の1行目は項目ラベルだということだから、startRowを「2」にして、表の2行目から値を取得しよう、というわけ。
(3)で
With wordTable_(tableNum)
このようにしているので、この後、End WithまではwordTable_(tableNum)に格納されたTableオブジェクト、すなわち「tableNum番目の表」が処理の対象となる。
(4)からの2行、
maxRow_ = .Rows.Count maxColumn_ = .Columns.Count
では、TableオブジェクトのRows、ColumnsコレクションのCountプロパティを用いて、変数maxRow_、maxColumn_に表の行数・列数をセットしている。
(5)では、(4)で取得した表の行数・列数を用いて
ReDim tableArray_(maxRow_, maxColumn_)
tableArray_()をReDimしている。
さて、ここからがこのメソッドの中心。
まず、(6)からの5行、
Dim iRow As Integer '……(6)' Dim iColumn As Integer Dim str As String Dim n As Integer n = 1
は、変数の準備。
iRow
Forループ(外側)のカウンタとして使用。Wordの表の行数指定を兼ねる。
iColumn
Forループ(内側)のカウンタとして使用。配列二次元目のインデックス、及びWordの表の列数指定を兼ねる。
str
表の各セルの文字列の受け取りに使用。
n
配列一次元目のインデックスの指定に使用。
Wordの表から値を取得するとき、1行目が項目ラベルなのかどうかによって、1行目から値を取得しはじめる場合と2行目から値を取得しはじめる場合の2通りがあるので、Forループのカウンタ以外に別途Wordの表の行数を指定するための変数nを準備し、「1」で初期化している。
そして、このメソッドの処理の中心が(7)からの7行。
For iRow = startRow To maxRow_ '……(7)' For iColumn = 1 To maxColumn_ '……(8)' str = .Cell(iRow, iColumn).Range.Text '……(9)' tableArray_(n, iColumn) = Left(str, Len(str) - 2) '……(10)' Next n = n + 1 '……(11)' Next
Forループがネストしているので、ちょっと見づらいかも知れないが、行方向のループと列方向のループだけなので、許容範囲だと思う。
まず、(7)、
For iRow = startRow To maxRow_
行方向のループ指定だが、開始値を変数startRowにしているのがミソ。
言うまでもなく、表の1行目から読み取る場合と2行目から読み取る場合の2種類に対応するためだ。
次の(8)、
For iColumn = 1 To maxColumn_
は、列方向のループ。各行につき、1列目から右へ右へと値を取得しては配列に格納していく、というイメージ。
(9)の
str = .Cell(iRow, iColumn).Range.Text
で、セルの文字列をstrに格納し、
(10)の
tableArray_(n, iColumn) = Left(str, Len(str) - 2)
で「ハナクソ」と改行文字を除去した上で配列にセットしている。
1行分セットし終えたら、すなわち、(8)のForループが完了したら、次の行に進むために、(11)の
n = n + 1
で変数nをインクリメントする。
このようにすれば、表内の全ての値が配列tableArray_()セットされるはずだ。
動作確認
このクラスの動作確認用に、次のコードを標準モジュールに書く。
リスト2
Public Sub testTableArray() Dim wtOperator As WordTableOperator Set wtOperator = New WordTableOperator wtOperator.createArrayFromTable 2, True '……(1)' Dim iRow As Integer Dim iColumn As Integer With wtOperator '……(2)' For iRow = 1 To .maxRow For iColumn = 1 To .maxColumn ActiveSheet.Cells(iRow, iColumn).Value = _ .tableArray(iRow, iColumn) Next Next End With Debug.Print wtOperator.tableArray(3, 3) '……(3)' End Sub
(1)の
wtOperator.createArrayFromTable 2, True
では、createArrayFromTableメソッドを、引数「2」と「True」の2つを渡して実行。
日本語訳すると、「2番目の表の値を、1行目が項目ラベルであるとみなして二次元配列としてプロパティに格納せよ」ぐらいか。
(2)からの8行(正味7行)、
With wtOperator For iRow = 1 To .maxRow For iColumn = 1 To .maxColumn ActiveSheet.Cells(iRow, iColumn).Value = _ .tableArray(iRow, iColumn) Next Next End With
は、もはや説明不要だろう。
二重のForループを用いて、tavleArrayプロパティにセットした値をアクティブシートに書き込んでいるだけだ。
あと、(3)の
Debug.Print wtOperator.tableArray(3, 3)
は、二次元のインデックスを渡して値を取得する例。
実行結果
このWordドキュメントがアクティブの状態で実行した。
Excelシート上に各値が転記されている。
イミディエイト・ウインドウには、2番目の表の3行3列目の値が表示されている。
おわりに
せっかく二次元配列として表のデータを取得しているのだから、tableArrayプロパティに表のデータを読み込ませた後、
With wtOperator ActiveSheet.Range("A1").Resize(.maxRow, .maxColumn).Value = .tableArray End With
とでも書けば、一発でExcelワークシートに転記できそうなものだが、
こんなふうにコンパイル・エラーになって、実行すらさせてくれない。
プロパティはあくまでもプロパティであって、配列変数ではない、ということなのかなあ?