
こちらの識者の方々にはいつもお世話になっています。
VBAの質問です。
環境は下記になります。
OS=windowsXP SP3
Office=Excel2003(11.8347.8403) SP3
会社などで一般的にVBAを使用してデータの処理をする場合、自動で吐き出されるcsvファイルを読み込んで、そのデータを加工し、使いたいデータに成型する。というケースが往々にしてあると思うのですが、吐き出されるcsvファイルのタイトル行が今までのものと同一でない(フィールドが知らないうちに増えたり減ったりしている)場合を想定し、csvファイルを取り込んだ時点でタイトル行の検査をしたいのですが、csvファイルのタイトル行を一旦配列に格納し、あらかじめ用意しておいたタイトル行のデータと比較する場合、配列内の一要素ずつ検査するしかないのでしょうか?
例としてはタイトル行が
"品名", "4月", "5月", "6月", "7月", "8月", "9月"
と仮定し、
Sub test()
Dim EndClm As Long
Dim TitleA As Variant
Dim TitleB As Variant
Dim i As Long
EndClm = Sheets(1).Cells(1, Columns.Count).End(xlToLeft).Column
TitleA = Workbooks("aa.csv").Sheets(1).Range(Sheets(1).Cells(1, 1),Sheets(1).Cells(1, EndClm)) 'csvファイルのタイトル行
TitleB = ThisWorkbook.Sheets(1).Range(Sheets(1).Cells(1, 1), Sheets(1).Cells(1, EndClm)) '検証用 "品名", "4月", "5月", "6月", "7月", "8月", "9月"
For i = 1 To UBound(TitleA, 2)
If TitleA(1, i) <> TitleB(1, i) Then MsgBox "項目が変更されています"
Next i
End Sub
のようなコードで1つずつ検証できますが、配列内の要素を一気に検証する方法はありますか?
当然通りませんが
If TitleA <> TitleB Then MsgBox "項目が変更されています"
のような感じです。
短いコードで確実にタイトル行の検査が行われれば、上記の配列に取り込んで要素を検証することに特に頓着はしていません。
今このテストコードを自宅のWindows7,Excel2010で書いていて思ったのですが、TitleA、TitleB共に配列に取り込む際、ブックをアクティブにしないとエラーが起きてしまいます。
もしよろしければこの原因も併せて教えていただいてもよろしいでしょうか。
質問に不備不足等ございましたらご指摘ください。
ご面倒お掛けしますがよろしくお願いします。
No.2ベストアンサー
- 回答日時:
こんにちは。
まず、修正を加えるなら、こんな感じ。
' ' ///
Sub testA()
Dim EndClm As Long
Dim TitleA As Variant
Dim TitleB As Variant
Dim i As Long
With ThisWorkbook.Sheets(1)
EndClm = .Cells(1, Columns.Count).End(xlToLeft).Column
TitleB = .Cells(1).Resize(, EndClm) '検証用 "品名", "4月", "5月", "6月", "7月", "8月", "9月"
End With
TitleA = Workbooks("aa.csv").Sheets(1).Cells(1).Resize(, EndClm) 'csvファイルのタイトル行, "7月", "8月", "9月"
For i = 1 To EndClm
If TitleA(1, i) <> TitleB(1, i) Then
MsgBox "項目が変更されています"
Exit For
End If
Next i
End Sub
' ' ///
"短いコード"とは言い難いですが、ループしない方法もある、ということで以下。
' ' ///
Sub testJ()
Dim EndClm As Long
Dim TitleA As Variant
Dim TitleB As Variant
With ThisWorkbook.Sheets(1)
EndClm = .Cells(1, Columns.Count).End(xlToLeft).Column
TitleB = .Cells(1).Resize(, EndClm) '検証用 "品名", "4月", "5月", "6月", "7月", "8月", "9月"
End With
TitleA = Workbooks("aa.csv").Sheets(1).Cells(1).Resize(, EndClm) 'csvファイルのタイトル行, "7月", "8月", "9月"
If Join(Application.Transpose(Application.Transpose(TitleA)), vbCr) _
<> Join(Application.Transpose(Application.Transpose(TitleB)), vbCr) _
Then MsgBox "項目が変更されています"
End Sub
' ' ///
要するにタイトルすべてを連結した文字列を比較する、という方法です。
単行複列の二次元配列を、ワークシート関数のTRANSPOSEに2回掛けると一次元配列が返ります。
一次元配列をJoin関数で連結した文字列を比較します。
(vbCrを区切り文字に指定するのは、セル内で使わることがない文字だからです。)
実践的には普通にループする方法の方が却って無駄が無いように思いますが、
ループしないことを好む向きもありましょうから、紹介まで。
csvファイルについては、単にテキストファイルとしての扱いが可能ですから、
Open "aa.csv" For Input As #1
Line Input #1, TitleA
Close #1
とかで、そのままタイトル行だけcsvテキストを取得しちゃう方が
部分的には簡単で処理も速く、正攻法な気がします。
(タイトル行に引用符を使うようなcsvだとシートとの比較が難しいですけれど)
比較するのが、どちらもcsvという場合なら、かなりの説得力を持って奨められるところですが、
片方がExcelブックだとちょっとアンバランスな漢字がするかも、です。
' ' ///
Sub testC()
'
Dim EndClm As Long
Dim TitleA As Variant
Dim TitleB As Variant
Dim nFree As Integer
With ThisWorkbook.Sheets(1)
EndClm = .Cells(1, Columns.Count).End(xlToLeft).Column
TitleB = .Cells(1).Resize(, EndClm) '検証用 "品名", "4月", "5月", "6月", "7月", "8月", "9月"
End With
nFree = FreeFile
Open "aa.csv" For Input As #nFree
Line Input #nFree, TitleA
Close #nFree
If TitleA <> Join(Application.Transpose(Application.Transpose(TitleB)), ",") _
Then MsgBox "項目が変更されています"
End Sub
' ' ///
さて、本題の「列内の要素を一気に検証する方法はありますか?」
というご質問について。
単行または単列の二次元配列または一次元配列を
丸ごと比較する機能、についてですが、
(#最近思いだしたのですが)ユーザー設定のリストを使う方法が簡単といえば簡単です。
但し、Excel2007以降の場合は、Excel97-2003互換ブックからの実行に限定されます。
これは裏技ですから、堂々と人に奨めるようなものではないです。
' ' ///
Sub testAJ()
Dim EndClm As Long
Dim TitleA As Variant
Dim TitleB As Variant
Dim i As Long
With ThisWorkbook.Sheets(1)
EndClm = .Cells(1, .Columns.Count).End(xlToLeft).Column
TitleB = .Cells(1).Resize(, EndClm) '検証用 "品名", "4月", "5月", "6月", "7月", "8月", "9月"
End With
TitleA = Workbooks("aa.csv").Sheets(1).Cells(1).Resize(, EndClm) 'csvファイルのタイトル行, "7月", "8月", "9月"
With Application
.AddCustomList TitleB ' 配列を引数にユーザー設定のリストを追加
' ' 引数にした配列がユーザー設定のリストの何番目にあるかを取得。無ければ、0。
If .GetCustomListNum(TitleA) = 0 Then MsgBox "項目が変更されています"
.DeleteCustomList .CustomListCount ' 追加したユーザー設定のリストを削除して元に戻す。
End With
End Sub
' ' ///
結論っぽいことを書くなら、お奨めするなら最初に挙げたtestAです。
個人的には、どれでも許せる記述ですけれど、人によって意見は分かれそうです。
そういう意味では、testAのように万人が理解できるものが一番安心して使える、と思います。
:testA
修正ありがとうございます。
たしかにRangeとCellsを組み合わせるよりかはResizeプロパティで書いたほうがすっきりしますね。
:testJ
transpose関数自体を知りませんでした。
Redimでは配列の次元数自体を変更できないようなのであきらめていたんですが、こういう技もあるんですね。
:testC
ブックを開かずデータを読み込む方法があるんですね。
たしかにこれだと、開く前に検査だけできるので使いやすいです。
:testAJ
配列の要素を一気に検証する方法も教えていただきありがとうございます。
やはり一般的ではないんですね。
おすすめ通りtestAか、両方csvの場合はtestCでやりたいと思います。
transpose関数を使った配列の次元数変更はとても参考になりました。
ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
七夕祭りの挨拶(介護施設)
-
月の最後の週の呼び名は?
-
エクセルのフィルターを複数シ...
-
昔の愛称?「~の字」
-
8月までっていつまでのことでし...
-
10月をもって辞めるって、10...
-
カレンダーの日付 5/Bの意味に...
-
学校の在籍機関
-
願望 春より秋がよし 思い立つ...
-
「6月まで」というのは6月以内...
-
入社が2月1日とした場合、3ヶ月...
-
月度ってどういう意味ですか
-
満何歳の意味
-
早生まれであることにコンプレ...
-
節句・平安時代の11月11日...
-
○月第○週 の数え方について
-
ピボットテーブルで列ラベルに...
-
高校生カップルがクリスマスにH...
-
自治会の通常総会の年度について
-
日本文化の中の七という数字の意味
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
カレンダーの日付 5/Bの意味に...
-
月の最後の週の呼び名は?
-
8月までっていつまでのことでし...
-
10月をもって辞めるって、10...
-
エクセルのフィルターを複数シ...
-
入社が2月1日とした場合、3ヶ月...
-
「6月まで」というのは6月以内...
-
自治会の通常総会の年度について
-
「1年以上」の定義について
-
定年になる年度を関数で算出したい
-
総会の年度表記について
-
満何歳の意味
-
昔は何歳くらいからお酒を飲ん...
-
昔の愛称?「~の字」
-
高校生カップルがクリスマスにH...
-
月度ってどういう意味ですか
-
確認ですが普通5月までに決める...
-
母の日、父の日っていつですか?...
-
例文「7月までは、このままで」と...
-
「おじろく」は長男が死んだら...
おすすめ情報