ここから本文です

vbcriptでcsvファイルの中身を編集する vbsにて、csvファイルを読み込み、 ...

rem********さん

2018/10/3000:09:54

vbcriptでcsvファイルの中身を編集する


vbsにて、csvファイルを読み込み、
以下のように編集することは可能でしょうか。

D&Dでスクリプトを実行することとします。

・実行前
作成日:2018年10月30日
氏名 性別 出身
tanaka 男 新潟
takeda 男 東京
ishida 男 東京
sato 男 東京

・実行後
tanaka 男 新潟 0001 PC
takeda 男 東京 0002 PC
ishida 男 東京 1001 スマートフォン
sato 男 東京 1002 スマートフォン


1.1,2行目を削除する
2.D列とE列に値を追加する
※D列の値は、0001の次は0002みたいにコードで連番になるようにする
※E列の値には、D列の値が「0001~0999」の場合、E列の値が「PC」
D列の値が「1001~1999」の場合、E列の値が「スマートフォン」と表示されるようにする
実際に、csvファイル内の値の数が多いため、汎用性があるコード、
また、よろしければ一文一文のコードの説明や、F列、G列に値がある場合にどうコードを追加すれば良いか
ご教示頂けると幸いです。

閲覧数:
623
回答数:
4
お礼:
100枚

違反報告

ベストアンサーに選ばれた回答

Prometheusさん

2018/10/3009:40:55

質問の主旨から、本来のデータは「1000」行以上存在する、と判断しています(もちろん、なくてもかまいませんが、その場合は、「スマートフォン」は出てきません)。

もし、元データが、

作成日:2018年10月30日
氏名,性別,出身
tanaka,男,新潟,a
takeda,男,東京,b
ishida,男,東京,c
sato,男,東京,d

などというように、列が多くても対応しています(最低「氏名,性別,出身」の3項目は必要です)。

tanaka,男,新潟,0001,PC,a
takeda,男,東京,0002,PC,b
ishida,男,東京,0003,PC,c
sato,男,東京,0004,PC,d

こちらで動作確認はしていますが、ある意味、元ファイルが無くなってしまいますので、必ず一度、ダミーのテストファイルで試してから、お使いください。

Option Explicit
Dim a, c, cv, dm, f, i, j, m, n, so, r, wa, x, y
Set so = CreateObject("Scripting.FileSystemObject")
Set wa = WScript.Arguments
For i = 0 to wa.Count - 1
If LCase(so.GetExtensionName(wa(i))) = "csv" Then
f = so.GetParentFolderName(wa(i))
Set cv = so.OpenTextFile(wa(i), 1)
Set dm = so.OpenTextFile(f & "\Dummy.csv", 2, True)
cv.SkipLine
cv.SkipLine
c = 0
Do Until cv.AtEndOfStream
a = Split(cv.ReadLine, ",")
c = c + 1
r = Right("000" & CStr(c), 4)
x = ""
For j = 0 to UBound(a)
If j = 2 Then
If c < 1000 Then
y = "PC"
Else
y = "スマートフォン"
End If
x = x & a(j) & "," & r & "," & y & ","
Else
x = x & a(j) & ","
End If
Next
dm.WriteLine Left(x, Len(x) - 1)
Loop
cv.Close
dm.Close
Set cv = Nothing
Set dm = Nothing
n = so.GetFileName(wa(i))
so.DeleteFile wa(i)
Set m = so.GetFile(f & "\Dummy.csv")
m.Name = n
End If
Next
Set wa = Nothing
Set so = Nothing
MsgBox("Finished!")

簡単な説明です。

Option Explicit

「厳密に」とか「明確に」というような意味で、このオプションを設定すると、変数は、その使用の前に、必ず、「Dim」等によって、宣言しておかなければなりません。

Set so = CreateObject("Scripting.FileSystemObject")

ファイルやフォルダを扱えるようにしていますが、今回は特に、「csv」というテキストファイルを扱うのにも必要です。

Set wa = WScript.Arguments

ドラッグ&ドロップされるのを待っています。

For i = 0 to wa.Count - 1

ドラッグ&ドロップされた内容は、1つ目=「wa(0)」、2つ目=「wa(1)」、3つ目=「wa(2)」、・・・というように格納されます。

この「wa(0)」などは、見た目は「配列変数」のようですが、配列変数ではありません。

「wa(0)」などは、ある意味ファイルそのものです。

「wa(0)」の内容は、「D:\Programming\Test_01.csv」などとなっていますが、いったん、ドラッグ&ドロップして、この情報が確定すると、以後、変更することは出来ません。

したがって、ファイル名順にソートしたいような場合は、他の配列変数に格納してその配列変数をソートすることになります。

「wa(0)」などのままでは、書き換えが出来ないので、ソートできないのです。

そして、ドラッグ&ドロップされたファイルの数は、「wa.Count」で分かります。

しかしい、「wa.Count」は5つドラッグ&ドロップしたら「5」を返しますが、実際に格納されてているのは「wa(0)」というように「0」から始まります。

そこで、「For i = 0 to wa.Count - 1」というように、「- 1」が必要なのです。

If LCase(so.GetExtensionName(wa(i))) = "csv" Then

「LCase()」は、英字を小文字にする関数です。

これで「Csv」や「CSV」も、すべて「csv」になります。

「so.GetExtensionName()」は、「Scripting.FileSystemObject」の機能を使って(頭の「so」)、ファイルの拡張子を取得します。

すなわち、ここは「もし、拡張子がcsvなら」となります。

f = so.GetParentFolderName(wa(i))

これから処理するファイルが存在するフォルダを調べています。

この処理にも、頭に「so」が付いているように、「Scripting.FileSystemObject」の機能を使っています。

Set cv = so.OpenTextFile(wa(i), 1)

「i」番目のファイルを「読み込み専用(=「1」)」で開いています。

Set dm = so.OpenTextFile(f & "\Dummy.csv", 2, True)

いったん、書き込み用に同じフォルダ内に「Dummy.csv」ファイルを「書き込み専用(=「2」)」で「新規作成を許可(=「True」)」しています。

この「Dummy.csv」ファイルは、処理終了後、削除しています。

cv.SkipLine
cv.SkipLine

2行読み飛ばし。

c = 0

行カウント用変数の初期化。

Do Until cv.AtEndOfStream

ドラッグ&ドロップしたファイルの終端まで処理。

a = Split(cv.ReadLine, ",")

1行読み込んで、区切り記号を使って、配列変数に格納しています。

今回は、「csv」ファイルということで、区切り記号は「,」です。

たとえば、読み込んだ1行が「a,b,c」の場合、「a(0) = "a"」、「a(1) = "b"」、「a(2) = "c"」となります。

c = c + 1

1行読み込んだので、1つカウント。

r = Right("000" & CStr(c), 4)

「0001」~「9999」のような文字列を作成して「r」に入れています。

x = ""

書き込み用変数の初期化。

For j = 0 to UBound(a)

「UBound()」は、配列変数の添え字(「()」内の数字)の最大値を返します。

上記の例でしたら、「a(2) = "c"」の「2」です。

したがって、その場合は、「For j = 0 to 2」と記述しているのと同じになります。

If j = 2 Then

「j」が「2」のとき(すなわち3番目の項目を処理しようとしているとき)、

If c < 1000 Then
y = "PC"
Else
y = "スマートフォン"
End If

「c」の値が「1000」未満なら「y = "PC"」とし、それ以外(「1000」以上)なら、「y = "スマートフォン」としています。

x = x & a(j) & "," & r & "," & y & ","

tanaka,男,新潟,0001,PC

というような文字列を作成しています。

Else

「j」の値が「2」以外の場合は、

x = x & a(j) & ","

普通に、読み込んだ項目を「x」に付け加えています。

Next

を、すべての項目で繰り返しています。

dm.WriteLine Left(x, Len(x) - 1)

「Dummy.txt」ファイルに書き出しています。

このとき、「x」には最後に不要な「,」があるため、それ以外の分だけ書き出しています。

すなわち、「Len(x)」で、「x」の長さが分かり、その「- 1」で、それより1文字少ない文字数を、Left(左=頭)から、抜き出しているわけです。

Loop

を、ファイルの終端まで繰り返しています。

cv.Close
dm.Close
Set cv = Nothing
Set dm = Nothing

両ファイルを閉じています。

n = so.GetFileName(wa(i))

ドラッグ&ドロップした方のファイル名を調べています。

so.DeleteFile wa(i)

ドラッグ&ドロップしたファイルを削除しています。

Set m = so.GetFile(f & "\Dummy.csv")

「Dummy.csv」ファイルのファイル名を変更するために、ファイルを取得しています。

m.Name = n

ファイル名をドラッグ&ドロップしたファイルを同じにしています。

End If
Next

を、ドラッグ&ドロップしたファイルの数だけ繰り返しています。

Set wa = Nothing
Set so = Nothing

「Set ~」で使用した変数は、その使用後、「Nothing」で解放しておきます。

MsgBox("Finished!")

いつ終わったか分からないので、最後に「Finished!」と表示しています。

  • 質問者

    rem********さん

    2018/10/3020:48:04

    とても丁寧なご説明ありがとうございます。
    希望通りのコードでした。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

ベストアンサー以外の回答

1〜3件/3件中

並び替え:回答日時の
新しい順
|古い順

30246kikuさん

2018/10/3012:32:46

> vbsにて、csvファイルを読み込み、
> D&Dでスクリプトを実行することとします。
> 一文一文のコードの説明や

&本日取得の ID ・・・・

この辺見ると、臭いますが・・・


一文一文 ・・・ 初心者さんなのでしょうか?
F列、G列 ・・・ 最終的には Excel での操作なのでしょうか?

Excel なら、標準モジュールにでも VBA 記述して
・素直に開いて
・対象ファイルか確認後
・1,2行目を削除して
・D 列部分に2列分挿入して
・D 列に =RIGHT("000"&ROW(),4)
・E 列に =CHOOSE(INT((ROW()-1)/1000)+1,"PC","スマートフォン")
・必要に応じて名前を変更した保存
すれば・・・
VBE 上で実行するので、何かあった時のデバッグは容易かと

とは言っても、以下 VBS でどうなりますか

> 汎用性があるコード、

ということなので、初めの2行で対象ファイルかチェックしています
最低限のもので・・・
結果ファイル名は、元のファイル名先頭に $ を付加したものにしてます
再度、その出来上がったファイルを処理させようとしても、
先頭2行を解釈して、スキップします

わからない部分は、返信いただければと・・・

なお、以下記述の Sub Samp1 以降、
そのまま標準モジュールに張り付けて、
引数に処理対象のファイル(フルパス)を指定するだけで動作します

どうなりますか


Dim i, args

Set args = WScript.Arguments
For i = 0 To args.Count -1
   Call Samp1(args(i))
Next
WScript.Echo "終了"

Sub Samp1(arg)
   Dim i, r, sPath, sFile, buf, v
   Const ForReading = 1, ForWriting = 2

   With CreateObject("Scripting.FileSystemObject")
      If (LCase(.GetExtensionName(arg)) <> "csv") Then Exit Sub
      sPath = .GetParentFolderName(arg) & "\"
      sFile = "$" & .GetFileName(arg)
      With .OpenTextFile(arg, ForReading)
         If (Not .AtEndOfStream) Then
            r = .ReadLine
            If (IsDate(Mid(r, InStr(1, r, ":", vbTextCompare) + 1))) Then
               If (Not .AtEndOfStream) Then
                  r = .ReadLine
                  If (InStr(r, "氏名") > 0) Then
                     If (Not .AtEndOfStream) Then
                        buf = Split(.ReadAll, vbCrLf)
                     End If
                  End If
               End If
            End If
         End If
         .Close
      End With

      If (IsArray(buf)) Then
         With .OpenTextFile(sPath & sFile, ForWriting, True)
            For i = 0 To UBound(buf)
               v = Split(buf(i), ",", 4, vbTextCompare)
               Select Case UBound(v)
                  Case 2
                     ReDim Preserve v(4)
                  Case 3
                     ReDim Preserve v(5)
                     v(5) = v(3)
               End Select
               If (UBound(v) > 3) Then
                  v(3) = Right("000" & i + 1, 4)
                  Select Case Int(i / 1000)
                     Case 0: v(4) = "PC"
                     Case 1: v(4) = "スマートフォン"
                  End Select
                  .WriteLine Join(v, ",")
               End If
            Next
            .Close
         End With
      End If
   End With
End Sub

不適切な内容が含まれている可能性があるため、非表示になっています。

投稿内容に関する注意

ジジさん

2018/10/3008:25:48

この実行後が

tanaka 男 新潟 0001 PC
takeda 男 東京 0002 PC
ishida 男 東京 0003 PC
sato 男 東京 0004 PC

か、または

・実行前
作成日:2018年10月30日
氏名 性別 出身
tanaka 男 新潟
takeda 男 東京





ishida 男 東京
sato 男 東京

と数千行あって

・実行後
tanaka 男 新潟 0001 PC
takeda 男 東京 0002 PC





ishida 男 東京 1001 スマートフォン
sato 男 東京 1002 スマートフォン

追加:D列の値が「2001~2999」の場合、E列の値が「ネコ缶」と表示されるようにする


とかならまだわかるけど、質問文ではste********さんの疑問通りに感じますね。
それを回答できたら自作自演者位ですよ。

プロフィール画像

カテゴリマスター

ste********さん

編集あり2018/10/3007:20:47

vbsよりはPowershellをお勧めしたいですが、どちらにせよD列の値が0001系になるのか1001系になるかがどこから判断できるのかを示して貰えないと、vbsでもPowershellでも作れません。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。

不適切な投稿でないことを報告しました。

閉じる