プロが教える店舗&オフィスのセキュリティ対策術

エクセルVBA C列に特定の文字列を含む行のみを抽出し、一つのExcelにまとめたい。

現在使用している、VBAの一部に、複数のCSVファイルを一つのエクセルにまとめる作業をする箇所があります。
しかし、CSVのファイルサイズが大きいと読み込みにどうしても時間がかかってしまうということで、抽出する行を限定したいと考えております。
以下は現在使用しているVBAの一部(抽出のみ)なのですが、
C列にA or B or Cと入っている場合のみ、その行ごとエクセルに取り込みたいと考えております。

VBAに詳しい方、どうぞご教授ください。
宜しくお願いします。


----現在使用しているもの--------------------------------------------------------

Sub LoadFiles() 'CSVファイルの読み込み
Dim CsvFileName As Variant
Dim Li As String
Dim Bf() As String
Dim r As Long
Dim ShMain As Worksheet
Dim FlNo As Integer
Dim FFlNo As Integer

Worksheets("Sheet1").Activate
With ThisWorkbook 'シート&パスの設定
Set ShMain = .Worksheets("Sheet1")
ChDrive .Path
ChDir .Path
End With

'複数のファイルの選択を可に設定
CsvFileName = Application.GetOpenFilename _
(filefilter:="CSVファイル(*.csv),*.csv", _
Title:="CSVファイル選択", MultiSelect:=True)
' If VarType(CsvFileName) = vbBoolean Then Exit Sub 'キャンセル時の処置
If VarType(CsvFileName) = vbBoolean Then End 'キャンセル時終了
r = 1 '行の初期値
For FlNo = 1 To UBound(CsvFileName) 'ファイル数分ループ
FFlNo = FreeFile '---使用可能なファイル番号取得
Open CsvFileName(FlNo) For Input As #FFlNo
Do Until EOF(FFlNo) '最終行までループ
Line Input #FFlNo, Li '一行読み込み
Bf = Split(Li, """,""") 'カンマで分割し配列に代入
If UBound(Bf) >= 0 Then '空白行の処理を飛ばす
With ShMain '1行分のデータをセルに出力
.Range(.Cells(r, 1), Cells(r, UBound(Bf) + 1)).Value = Bf
End With
End If
r = r + 1
Loop
Close #FFlNo
Next FlNo
End Sub

質問者からの補足コメント

  • コメントありがとうございます。

    読み込む量が多いとパソコンのスペックによって、途中でVBAが止まってしまうことが多々ありましたので、時間というよりも読み込む量の少なさを重視したいと考えております。
    もちろん早いに越したことはありません。

    No.1の回答に寄せられた補足コメントです。 補足日時:2017/12/15 11:53
  • ありがとうございます。
    うまく実行できたのですが、取り込んだデータの最初の方の行に空白(おそらくC列が空白で処理を飛ばした分の行)が出来てしまいました。

    原因がちょっとわかりません....

    No.2の回答に寄せられた補足コメントです。 補足日時:2017/12/15 13:48

A 回答 (2件)

こんにちは



>If UBound(Bf) >= 0 Then '空白行の処理を飛ばす
で空白行を除いているのと同様に、条件に合わない行は記入処理をしなければ良いのではないでしょうか。

>C列にA or B or Cと入っている場合のみ、
が、該当条件なので「上の条件かつ空白行でなければ」という条件に変えれば良さそうです。
C列の値は配列の3番目なので、
 Bf(LBound(Bf) + 2)
で取得できますが、このままいきなり実行すると、元のデータがB列で終わっていたりするとエラーになってしまいますので、まず、C列にデータが存在することをチェックしておく必要がありますね。

ということで、例えばC列の値を、一旦、変数cvに代入するとして
 cv = ""
 If LBound(Bf) + 2 <= UBound(Bf) Then cv = bf(LBound(Bf) + 2)
で取得できます。(値が無い場合は、空白文字列になる)

>C列にA or B or Cと入っている場合のみ
といのが「"A"または"B"または"C"が入っている場合」という意味なのか、「"A or B or C"が入っている場合」という意味なのか曖昧ですが、とりあえず前者と考えて、「cvが"A"か"B"か"C"で、かつ、空白行でなければ」という条件にすればよいことがわかります。
一方、空白行の場合は、cvを取得する際にcv=""となりますので、結局、cvの値のチェックだけで良いことになります。

長々と書きましたが、
 >If UBound(Bf) >= 0 Then '空白行の処理を飛ばす
の部分を
 cv = ""
 If LBound(Bf) + 2 <= UBound(Bf) Then cv = bf(LBound(Bf) + 2)
 If (cv = "A" Or cv = "B" Or cv = "C") Then
の3行に置き換えれば良いのではないでしょうか。


話は変わりますが…
ご提示の方法ではcsvをテキストとして1行ずつ読み込む方法をとっていますが、csvデータはエクセルで直接シートに読み込むことが可能なので、方法としては大分異なりますが、
 1)csvデータを読み込む(エクセルがシートに展開)
 2)シート上で不要なデータを削除
 3)残ったデータを、所定のセル範囲へコピペ
のような手順の方が扱いやすいのではないかと思います。

ご提示の方法でも結局は全部のデータを走査していますので、ScreenUpdatingをオフにしておけば、処理時間が大幅に変わることはないのではないでしょうか。(速くなる可能性もあると思います)
この回答への補足あり
    • good
    • 0

念の為の確認ですが、目的は時間を短縮するためでしょうか?


それでしたら1行ごと判断して1行ごとの挿入になるので返って時間はかかります。
エクセルの場合まとめての処理の方が圧倒的に早くなりますよ。
この回答への補足あり
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A