では前回までで行ったCSV読み込みの処理に加えて今度はそれらの扱いについてやっていきましょう。
データベースの特性について考える
CSVはテキストファイルですが、いわゆるデータベースとして扱われるパターンが多いかと思われます(業種によって違うかも知れませんが…)
一意の値となるユニークなカラムはないにせよ、見出しとなるものはあるはずです。
例えば…
- 日付
- 住所
- 電話番号
などですね。
CSVファイルの見出し文字に注目
いつも使うCSVは同じ分類のものが多いでしょう。
つまり、見出しの文字もいつも同じというパターンがほとんどだと思います。
例えばこのようなCSVがあったとします。
一番上の行は見出しです。
ここから名前と住所だけを抜き出してみましょう。
見出しの配列を作る
抜き出したいカラムは名前と住所でしたね。見出しとなる文字は「名前」と「住所」なのでこの文字列の配列をArray関数というものを使用して作ってみましょう。Array関数で作られた配列はVariant型の変数に格納する事が出来ます。
Sub csv_to_array()
Dim header As Variant
header = Array("名前", "住所")
End Sub
この様にカンマで区切られたものが配列として格納されます。
CSVからカラムを求める
欲しい見出しの配列が出来た所でそれが何列目にあるのかを配列に格納していきましょう。
この場合は配列として宣言してから変数headerのUboundと同じ要素数でRedimすれば大丈夫ですね。
CSVを読み込んでからCSVファイルの1行目だけを読み込んでカラム数を取得していきましょう。
Sub csv_to_array()
Dim header As Variant
Dim hCol() As Long
Dim csv As Variant
Dim i As Long
Dim j As Long
header = Array("名前", "住所")
ReDim hCol(UBound(header))
csv = csvArr(filePath)
' 見出しの文字列が存在するColumnを取得
For i = LBound(header) To UBound(header)
For j = 0 To UBound(Split(csv(1), ","))
If Split(csv(1), ",")(j) Like header(i) Then
hCol(i) = j
Exit For
End If
Next
Next
End Sub
CSVデータをSplitで分解しつつ配列に格納
では1行毎にSplitで分解しながら格納していきましょう。
まずCSVから取得したデータの1行目から最終行までをループ。
データを入れる配列の1次元目をCSVの行数に設定。2次元目を取得したい見出しの数に設定。
配列名がdataだとするとRedim data(Ubound(csv), Ubound(header))となります。
しかし、csvファイルは0番目の要素が空、1番目の要素が見出しとなる為
Redim data(Ubound(csv) - 2, Ubound(header))
としなければ空の要素と必要ない要素がdataに出来てしまいますので気をつけましょう。
更にColumnを取得したhColという変数をLbound + 2(CSVの1行目は空、1行目は見出しの為)からUboundまで回って配列を格納していきます。
Sub csv_to_array()
Dim header As Variant
Dim hCol() As Long
Dim csv As Variant
Dim i As Long
Dim j As Long
Dim data() As String
header = Array("名前", "住所")
ReDim hCol(UBound(header))
csv = csvArr(filePath)
' 見出しの文字列が存在するColumnを取得
For i = LBound(header) To UBound(header)
For j = 0 To UBound(Split(csv(1), ","))
If Split(csv(1), ",")(j) Like header(i) Then
hCol(i) = j
Exit For
End If
Next
Next
' 配列に格納していく
ReDim data(UBound(csv) - 2, UBound(header))
For i = LBound(csv) + 2 To UBound(csv)
For j = LBound(hCol) To UBound(hCol)
data(i - 2, j) = Split(csv(i), ",")(hCol(j))
Next
Next
' 最後にセルに出力
Cells(1, 1).Resize(UBound(data, 1) + 1, UBound(data, 2) + 1) = data
End Sub
出力結果を確認
ここまでプログラムを走らせてみたらA1セルから配列の要素分だけ出力されているか確認してみましょう。
ちゃんと狙い通り出力されていますね。
今回のような手順を踏んだ理由
ではなぜ今回
- 見出しの文字列を配列に格納
- 見出し文字列が入っている配列からColumnを取得。配列に格納
という手順を踏んだのかというと
欲しい情報は増える可能性がある為、欲しい情報が増えた時はArray関数に与えている引数に欲しい見出し文字列を与えるだけで済むからなんです。
上司からの指示で欲しい情報を切り替えたり増やしたりする時に毎度毎度プログラムを複数個所書き換えるのは大分苦痛ですし時間の無駄です。
最初に作る時はちょっと面倒ですが後々の事を考えて作るとメンテや拡張が楽になります。
まとめ
業種によってはCSVからの情報の取得がすごく重要になると思います。
最初に工夫する事により後々のメンテにかける時間が大幅に変わってきますのでCSVを扱うお仕事をされている方は参考にしていただければ幸いです。
<<<CSVを取り込む順序を考える デバッグ方法を使い分ける>>>