
こちらの識者の方々にはいつもお世話になっています。
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で質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) VBA 請求書自動作成 3 2022/04/24 01:58
- Visual Basic(VBA) まとめシートから集計シートへA列のコードが一致したら1行コピーするマクロをネット上で見つけました。こ 1 2022/08/30 14:11
- Visual Basic(VBA) 複数csvを横に追加していくマクロについて 2 2023/04/25 09:19
- Visual Basic(VBA) フォルダの場所を可変にしたいです(マクロ) 4 2023/05/11 10:00
- Visual Basic(VBA) 複数のcsvファイルをExcelに一括変換したい 2 2023/03/03 12:44
- その他(Microsoft Office) マクロVBAについて 1 2022/09/06 18:12
- Excel(エクセル) マクロで最終行から上に検索を逆にしたい 1 2022/05/17 18:27
- Visual Basic(VBA) ファイル全てを .xlsm に変更したところ、プログラムが途中で落ちてしまっています 17 2022/12/07 12:03
- Visual Basic(VBA) 別シートから年齢別の件数をカウントしたいの続き 5 2023/01/24 00:16
- Excel(エクセル) Excel VBAどこが間違ってますか? 4 2023/07/17 10:04
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
自治会の通常総会の年度について
-
月の最後の週の呼び名は?
-
カレンダーの日付 5/Bの意味に...
-
「6月まで」というのは6月以内...
-
10月をもって辞めるって、10...
-
8月までっていつまでのことでし...
-
エクセルのフィルターを複数シ...
-
総会の年度表記について
-
入社が2月1日とした場合、3ヶ月...
-
母の日、父の日っていつですか?...
-
本願寺教如書状
-
昔は何歳くらいからお酒を飲ん...
-
定年になる年度を関数で算出したい
-
足かけ~年の足かけとは?
-
確認ですが普通5月までに決める...
-
昔の愛称?「~の字」
-
8月、働かなくても生活出来ます...
-
董卓の酒池肉林って、具体的に...
-
「なんで付き合おうと思ったか...
-
月度ってどういう意味ですか
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
自治会の通常総会の年度について
-
カレンダーの日付 5/Bの意味に...
-
確認ですが普通5月までに決める...
-
月の最後の週の呼び名は?
-
エクセルのフィルターを複数シ...
-
総会の年度表記について
-
8月までっていつまでのことでし...
-
入社が2月1日とした場合、3ヶ月...
-
「6月まで」というのは6月以内...
-
10月をもって辞めるって、10...
-
「1年以上」の定義について
-
昔の愛称?「~の字」
-
昔は何歳くらいからお酒を飲ん...
-
御入園?ご入園?
-
定年になる年度を関数で算出したい
-
月度ってどういう意味ですか
-
満何歳の意味
-
「なんで付き合おうと思ったか...
-
○年後の3月末日を関数で出したい
-
何故か毎年3月や4月に不運が続...
おすすめ情報