ExcelVBAでCSVFileをジャグ配列に格納する方法とは?

このQ&Aのポイント
  • ExcelVBAを使用して、CSVFileをジャグ配列に格納する方法について教えてください。
  • 行の添字と列の添字が1から始まるジャグ配列をExcelVBAで生成する方法について教えてください。
  • ExcelVBAでCSVFileを配列に格納する際に、ジャグ配列を1オリジンにする方法について教えてください。
回答を見る
  • ベストアンサー

ジャグ配列生成時の1オリジン

ExcelVBAで、CSVFileを取込み、シートを介さずに 配列へ格納する処理をしています。 尚、一行のデータの数が変わる可能性があるため、 ジャグ配列にしています。  Dim FileNamePath As Variant 'CSVファイルパス  Dim CSVFile() As Variant  Dim ch1 As Long  Dim RowCnt As Long ~略~  ch1 = FreeFile  Open FileNamePath For Input As #ch1  RowCnt = 1  Do While Not EOF(ch1)   ReDim Preserve CSVFile(RowCnt)   Line Input #ch1, CSVFile(RowCnt)   CSVFile(RowCnt) = Replace(CSVFile(RowCnt), """", "")   CSVFile(RowCnt) = Split(CSVFile(RowCnt), ",")   RowCnt = RowCnt + 1  Loop ~略~ この時、後の処理でやりやすくするために配列の添字を 1からにしたく、行の添字となるRowCntを1としています。 同様に列となる添字も1からとしたくて、モジュールの宣言にて 「Option Base 1」としましたが、上記コードでジャグ配列を 生成すると、(多次元配列で言う)2次元目の添字は 0からとなってしまいます。  例:CSVFile(1)(0) このような状況で、ジャグ配列でも1オリジンとするには どのようにすれば良いのでしょうか。 宜しくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.2

こんにちは。 >BシステムのExportFileに変更 そのままExcelではないのですか?そうすると、答えが違ってきます。 そうなら、Excelは必要ないですね。 その出力仕様は分からないのですが、Jug を受け入れられる他のソフトウェアって、Adobe 系列ぐらいしか思いつきません。ExcelのImport は、2次元で可能です。 なお、Option Base 1 は、使わないようにしました。 >何か出来る方法は無いかなと今回思っていました。 簡単なコードですが、このようにすれば出来ると思います。 '----------------------------------------- Sub SampleMacro1()   Dim FileName As Variant   Dim TextLine As String   Dim CSVFile() As Variant   Dim buf As Variant   Dim FNo As Integer   Dim i As Long   Dim j As Long   Dim u As Integer      FileName = Application.GetOpenFilename("CSV ファイル(*.csv),*.csv", 1, _   "ファイル・インポート")   If VarType(FileName) = vbBoolean Then Exit Sub      FNo = FreeFile()   Open FileName For Input As #FNo   i = 1 '初期値   Do While Not EOF(FNo)     Line Input #FNo, TextLine     buf = Replace(TextLine, """", "")     buf = Split(buf, ",")     u = UBound(buf)     ' Cells(i, 1).Resize(, u).Value = buf     buf = SlideArray(buf)     ReDim Preserve CSVFile(1 To i)     CSVFile(i) = buf     i = i + 1   Loop   Close #FNo End Sub Function SlideArray(ar As Variant) As Variant   '1次元の配列の添え字初期値を1にずらす   Dim arbuf As Variant   Dim i As Long   Dim v As Variant   If Not IsArray(ar) Then Exit Function   ReDim arbuf(1 To UBound(ar) + 1)   i = 1   For Each v In ar     If IsNumeric(v) Then       arbuf(i) = CDbl(v)     Else       arbuf(i) = v     End If     i = i + 1   Next v   SlideArray = arbuf End Function

langsam
質問者

お礼

おはようございます。 確認が遅くなってしまいました。 なるほど、別配列に移して作り直す処理をFunction化しているのですね。これなら分かりやすいですし、希望の処理が可能になります。 ありがとうございます!

その他の回答 (2)

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.3

#2の補足 #1の発言内容と、#2のコードは違うことは、予めご了解ください。Excelのワークシートに出すだけだと思ったから、そのまま1行ずつしてよいと申しましたが、それを、ジャグのままで、CSVFileに格納するとなると、相手のソフトウェアの仕様の問題があると思いますし、それを、添え字初期値が、0か1かは、微妙に左右してくるかもしれないと思い、前言の内容を変えました。なお、#2のコードは、出力はしていませんが、変数の格納でお分かりにはなると思います。 Excelを利用するなら、もちろん、シートを利用してもよいとは思いますが、その分、書き込みには、Rangeオブジェクトを使いますから、オーバーヘッドが掛かってしまいます。なお、変数は、Variant 型で、多次元配列を使っていますから、巨大なファイル構造には向きません。

langsam
質問者

お礼

たびたびのご回答、及び補足説明まで、誠に有難う御座います! #2についても、すぐに理解できました。 そうなんですよね、Rangeを使うとどうしても重くなってしまって・・・。 またご質問することもあると思います。その際には是非、宜しくお願い致します。

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.1

こんにちは。 全体的にみると、一気に、配列変数に納めようとしているらしいですが、そういうコードで最後まで持っていくのは、よほどVBAに自信があるのでしょうか。 最終段階が見えていないので、はっきりは断言できないのですが、そんな厄介なことをしないで、私なら、一行ずつ処理しますね。それで、大勢に影響ないからです。 >  ReDim Preserve CSVFile(RowCnt) >  Line Input #ch1, CSVFile(RowCnt) テキスト・ストリームをいきなり、配列の中に入れて、   CSVFile(RowCnt) = Replace(CSVFile(RowCnt), """", "") 配列の中で処理していますね。それも、   CSVFile(RowCnt) = Split(CSVFile(RowCnt), ",") 配列の中で、さら、分割して配列で入れて、ジャグにしているようです。 Split 関数の中の配列を、もう一度組みなおさなくては、1からにはなりません。 単に格納するのに、添え字を1とか0とか、まったく関係がないと思いますし、貼り付けも関係ありません。マトリックスの初期値が、(0,0)も(1,0)も、(1,1)も、位置をずらせばよいだけです。だから、次世代言語は、廃止になったわけですね。 RowCnt = 1  '←いらないです。 ReDim Preserve CSVFile(RowCnt) 最終的に貼り付ける目的で、UBound の1次元、2次元の添え字を得たら、その領域を、+1 づつ加えればよいわけです。たぶん、Resizeを使うとは思います。

langsam
質問者

補足

Wendy02様、こんにちは 早速のご回答、誠に有難う御座います。 一部だけを抜き取ったため分かりにくくなり申し訳ありません。 このマクロは、Aシステムの受入Formatに対応させるため、BシステムのExportFileに変更、追記をして出力するというものです。なので、追記用のデータマスタ以外にはシートを使用する必要がなく、貼付が終局ではありませんでした。すみません、回答材料が足りていませんでした。 また、VBAに自信だなんてとんでもないΣ('Д';シートを使う必要がないために、配列で済ましてしまおうと横着をしたようなものです。 ____________ >>Split 関数の中の配列を、もう一度組みなおさなくては、1からにはなりません。 baseを1にしてSplitを使うのは初めてだったのですが、Splitによって生成される配列の添字は、OptionBaseに関係なく0になるのですね! HelpのSplit関数項目に注記がなかったため大丈夫なのかと思っていました。 ____________ >>単に格納するのに、添え字を1とか0とか、まったく関係がないと思いますし、貼り付けも関係ありません。 私も同意見です。ただその上で、何か出来る方法は無いかなと今回思っていました。 今回のようにどうしてもsplitを使って一括で1を始点にしたければ、 CSVFile(RowCnt) = "," & Replace(CSVFile(RowCnt), """", "") とでもして0を無視するくらいしか無さそうですね(^^; ____________ >>RowCnt = 1  '←いらないです。 ああーすみません。前の処理で使った値の初期化でした。紛らわしかったですね。 ____________ >>私なら、一行ずつ処理しますね。 僭越ながら私も、一行ずつ処理をするという考え方で作っていました。 もしよろしければWendy02様の一行ずつ処理をするというロジックを、簡単で結構ですので教えていただけませんでしょうか。

関連するQ&A

  • CSVの読み込み処理について

    こんばんわです。 エクセルのVBAをつかってCSV形式のファイルデーターを読み込みように某サイトを参考に作成しました。 確かに読み込む事が出来たのですが、数値も文字列扱いになってしまいます。 数値処理する方法があるのでしょうか? Sub CSV_Read2() Dim FileType, Prompt As String Dim FileNamePath As Variant Dim textline, csvline() As String Dim Rowcnt, ColumNum As Integer Dim ch1 As Long FileType = "CSV ファイル (*.csv),*.csv" Prompt = "CSV File を選択してください" '操作したいファイルのパスを取得します FileNamePath = SelectFileNamePath(FileType, Prompt) If FileNamePath = False Then 'キャンセルボタンが押された End End If '空いているファイル番号を取得します ch1 = FreeFile 'FileNamePath のファイルをオープンします Open FileNamePath For Input As #ch1 'エラーが発生したらファイルを閉じます 'CSVのファイルは1行の項目数が正確に合っていないと読めないのですが、 '色々なCSVがあるようなので入れておきます On Error GoTo CloseFile '表の行番号の初期化 1行目から読み込んだデータを入力します Rowcnt = 1 Do While Not EOF(ch1) 'ファイルの終端かどうかを確認します。 '1行読み込みます Line Input #ch1, textline 'ダブルクォーテーションを削除します 'カンマ+ダブルクォーテーションで区切られている CSV ファイルなどは '適時追加してください textline = Replace(textline, """", "") 'カンマで分離します csvline() = Split(textline, ",") '配列渡しでセルに代入 Range(Cells(Rowcnt, 1), Cells(Rowcnt, UBound(csvline()) + 1)) = csvline() Rowcnt = Rowcnt + 1 Loop CloseFile: 'ファイルを閉じます Close #ch1 End Sub Function SelectFileNamePath(FileType, Prompt) As Variant SelectFileNamePath = Application.GetOpenFilename(FileType, , Prompt) End Function Function GetItemNum(FileNamePath) As Integer Dim ch1 As Long Dim textline As String '空いているファイル番号を取得します ch1 = FreeFile 'FileNamePath のファイルをオープンします Open FileNamePath For Input As #ch1 Line Input #ch1, textline '1行だけ読み込みます。 Close #ch1 GetItemNum = 1 '1行中のカンマの数を数えます Do GetItemNum = GetItemNum + 1 textline = Mid(textline, InStr(textline, ",") + 1) Loop Until InStr(textline, ",") = 0 End Function

  • \記号が入った数値の処理について(VBA)

    はじめまして。 excel2013でcsvの読み込みをVBAで自動化させようとしています。 基となるCSVファイルに\記号が含まれておりファイルを読み込むと文字列として読まれてしまいまい、エラーインジケータが表示されます。 文字と読み込まれているので計算もできないでいます。 数値に置き換える方法として考えられる事はないでしょうか? ご教授お願いいたします。 ------------------------------- ソース Sub Read() Dim FileType, Prompt As String Dim FileNamePath As Variant Dim csvline() As String Dim i, Rowcnt, ColumNum As Integer Dim ch1 As Long FileType = "CSV ファイル (*.csv),*.csv" Prompt = "CSV File を選択してください" '操作したいファイルのパスを取得します FileNamePath = SelectFileNamePath(FileType, Prompt) If FileNamePath = False Then 'キャンセルボタンが押された End End If '1行あたりの項目数を取得します ColumNum = GetItemNum(FileNamePath) 'csvlineを1行あたりの項目数で再割り当てます ReDim csvline(1 To ColumNum) '空いているファイル番号を取得します ch1 = FreeFile 'FileNamePath のファイルをオープンします Open FileNamePath For Input As #ch1 'エラーが発生したらファイルを閉じます 'CSVのファイルは1行の項目数が正確に合っていないと読めないのですが、 '色々なCSVがあるようなので入れておきます On Error GoTo CloseFile '表の行番号の初期化 1行目から読み込んだデータを入力します Rowcnt = 1 Do While Not EOF(ch1) 'ファイルの終端かどうかを確認します。 For i = 1 To ColumNum Input #ch1, csvline(i) '1行の項目数だけ読み込みます Next '配列渡しでセルに代入 この方が早い Range(Cells(Rowcnt, 1), Cells(Rowcnt, ColumNum)) = csvline() Rowcnt = Rowcnt + 1 Loop CloseFile: 'ファイルを閉じます Close #ch1 End Sub Function GetItemNum(FileNamePath) As Integer Dim ch1 As Long Dim textline As String '空いているファイル番号を取得します ch1 = FreeFile 'FileNamePath のファイルをオープンします Open FileNamePath For Input As #ch1 Line Input #ch1, textline '1行だけ読み込みます。 Close #ch1 GetItemNum = 1 '1行中のカンマの数を数えます Do GetItemNum = GetItemNum + 1 textline = Mid(textline, InStr(textline, ",") + 1) Loop Until InStr(textline, ",") = 0 End Function Function SelectFileNamePath(FileType, Prompt) As Variant SelectFileNamePath = Application.GetOpenFilename(FileType, , Prompt) End Function ----------------------- CSVファイル \101,\101,\101

  • 二次元配列のVBA

    二次元配列のVBAの書き方がよくわからないのですが、 私が作ったサンプルプログラムのSub 二次元()において 二次元配列で表すにはどうすればいいのでしょうか? Sub 二次元()では 配列を格納する変数はtmpしか使っていませんが もう一つ配列を格納する用の変数を作ればいいのでしょうか? 数字とアルファベットは別々に取り出したいです。 ----------------------------------------------------- Sub 一次元() Dim myStr As String Dim tmp As Variant Dim i As Long For i = 1 To 5 myStr = myStr & "," & i Next myStr = Mid(myStr, 2) tmp = Split(myStr, ",") For i = LBound(tmp) To UBound(tmp) Debug.Print tmp(i) Next i End Sub Sub 二次元() Dim myStr As String Dim tmp As Variant Dim i As Long For i = 1 To 5 myStr = myStr & "," & i & "と" & Chr(64 + i) Next myStr = Mid(myStr, 2) tmp = Split(myStr, ",") For i = LBound(tmp) To UBound(tmp) Debug.Print tmp(i) Next i End Sub

  • 3次元配列の記述

    VB6.0を使っています。 2次元配列は以下の様になりますが、3次元配列はどう記述すればいいのでしょうか? Dim phrase(1) As Variant phrase(0) = Array("0-0", "0-1", "0-2") phrase(1) = Array("1-0", "1-1", "1-2")

  • エクセルVBAでのCSV出力方法について

    エクセルVBAを使ってCSVを出力しようとしているのですが、 狙った範囲を上手くCSV化することが出来ずに苦戦しています。 どなたかアドバイスを頂けませんでしょうか。 使用してるエクセルは2010になります。 シート2のコマンドボタンを押すことでシート1の内容をCSV化したいと考えています。 シート1のA1に入力した内容がCSVのタイトルになります。 2行目はヘッダーですが、CSVには反映しないように制御をかけています。 ↓が実際に書いてみたVBAですが、どうしてもシート1の内容を持ってきてしまいます。 どのように改修したらシート2の内容を持ってこれるでしょうか。 Private Sub CommandButton1_Click() Dim MyFile, FileType, Prompt As String Dim FileNamePath As Variant Dim StartRow, StartCol, EndRow, EndCol As Integer Dim Rowcnt, Colcnt As Integer Dim UsedCell As Range Dim ch1 As Long '対象のシートをアクティブにする Worksheets("シート1").Activate 'ファイル名の取得 MyFile = ActiveSheet.Range("A1") & ".csv" FileType = "CSV ファイル (*.csv),*.csv" Prompt = "保存するファイルの名前を付けてください" '保存するファイルのパスを取得します FileNamePath = SaveFileNamePath(MyFile, FileType, Prompt) If FileNamePath = False Then 'キャンセルボタンが押された End End If '空いているファイル番号を取得します ch1 = FreeFile 'FileNamePath のファイルをオープンします Open FileNamePath For Output As #ch1 '使用しているセルの取得 Set UsedCell = ActiveSheet.UsedRange StartRow = UsedCell.Cells(3).row StartCol = UsedCell.Cells(1).Column EndRow = UsedCell.Cells(UsedCell.Count).row EndCol = UsedCell.Cells(UsedCell.Count).Column For Rowcnt = StartRow To EndRow For Colcnt = StartCol To EndCol - 1 '改行を挿入しないで書き出す ; を最後に付ける Write #ch1, Cells(Rowcnt, Colcnt); Next '改行を挿入する Write #ch1, Cells(Rowcnt, EndCol) Next 'ファイルを閉じます Close #ch1 End Sub Function SaveFileNamePath(MyFile, FileType, Prompt) As Variant SaveFileNamePath = Application.GetSaveAsFilename(MyFile, FileType) End Function アドバイスを頂けたらと思います。 どうぞ宜しくお願いします。

  • このようなエクセルマクロを作りたいのですが・・・

    ,で区切られたasc形式のファイルを、エクセル上に出力したいです。 ファイルは大体12万行くらいあります。 やりたいこと) 1. 任意のファイルを読み込む。 2. ,毎に区切って「数値」として出力する。(,は2つあるので、データはABC列に出力されることになります) 3. 32000行を越えたら、DEF列に出力する。 4. DEF列でも再び32000行(合計64000行読み込んだ)を越えたらGHI列に・・・ 5.データがなくなったら終了 ということがやりたいです。 現在、ファイルを読み込んで区切るところまでは出来たのですが、3のところで躓いています。ソースを書いておきますので、どのようにやればいいのでしょうか? 途中で、IF Rowcnt > 32000 then・・・とやると上手くいきそうなのですが、様々なエラーに阻まれてお手上げです・・・ また、このマクロで出力すると、必ず「文字列」として出力されてしまうのですが、どうやれば最初から「数値」として出力してくれるのでしょうか?どこか宣言を誤ったのでしょうか・・・ つたない文章ですが、ご指導のほどよろしくお願いいたします。 Sub CSV_Read() Dim FileType, Prompt As Variant Dim FileNamePath As Variant Dim csvline() As String Dim i, Rowcnt, ColumNum As Integer Dim ch1 As Variant FileType = "asc ファイル (*.asc),*.asc" Prompt = "ファイルを選択してください" FileNamePath = SelectFileNamePath(FileType, Prompt) If FileNamePath = False Then End End If ColumNum = GetItemNum(FileNamePath) '1行あたりの項目数を取得します ReDim csvline(1 To ColumNum) 'csvlineを1行あたりの項目数で再割り当て ch1 = FreeFile Open FileNamePath For Input As #ch1 'FileNamePath のファイルをオープンします On Error GoTo CloseFile Rowcnt = 1 Do While Not EOF(ch1) 'ファイルの終端かどうかを確認。 For i = 1 To ColumNum Input #ch1, csvline(i) '1行の項目数だけ読み込み Next Range(Cells(Rowcnt, 1), Cells(Rowcnt, ColumNum)) = csvline() Rowcnt = Rowcnt + 1 Loop CloseFile: Close #ch1 End Sub

  • Access VBA での配列

    Access VBAで下記のような配列(ジャグ配列?)を作りたいと考えています。 添字[0] = ("0A","0B","0C") 添字[1] = ("1A","1B","1C","1D") VB.NETでは下記のような感じで書けたと思います。 Dim strArray(1) As Object strArray(0) = New String(2) {"0A", "0B", "0C"} strArray(1) = New String(3) {"1A", "1B", "1C", "1D"} 分かりましたら是非教えてください。 お願いします。

  • VBAでCSVファイルを読み込もうとしていますが、

    VBAでCSVファイルを読み込もうとしていますが、 「ファイルが見つかりません」とエラーが表示されます。 どのように対処していいのかわかりません。 教えてくください。 Sub readCsv() Dim csvFile As String Dim ch As Integer Dim csvStr As String Dim str() As String Dim i As Integer Set ShellApp = CreateObject("Shell.Application") Set oFolder = ShellApp.BrowseForFolder(0, "フォルダ選択", 1) targetFolder = oFolder.Items.Item.Path Set fso = CreateObject("Scripting.FileSystemObject") Set fileList = fso.GetFolder(targetFolder).Files For Each file In fileList csvFile = file.Name ch = FreeFile Open csvFile For Input As #ch i = 1 Do While Not EOF(1) Line Input #ch, csvStr Close #ch str = Split(csvStr, ",") Range(Cells(i, 1), Cells(i, UBound(str) + 1)) = str i = i + 1 Loop Next End Sub

  • VBAの動的配列について

    いつもお世話になっております。 エクセルVBAを学習中の者です。 動的配列についてお伺いします。 添付資料を見て頂きたいのですが、 シート名1~4に同一レイアウトの表があります。 これらの表をを2次元配列に格納し、その後、同一レイアウトのシートに一括転記したいと考えています。 転記の事を考えて、条件としては、 シート1から2行目以降のデータを配列『data』に格納、変数『dataCnt』が転記先の行番号と同じになるように考えています。 当初は、配列の定義を『Dim data(100,3) As Variant』と、多めに要素数を定義して、コードを記述していました。 正直、凄く気持ちが悪い感じでした・・・ 最近、動的配列を学習しまして、 シートごとにデータの行数を変数『lastRow』に格納して、配列を再定義して【データ数=要素数】とならないか? と思い、下記のようなコードを書いてみました。 が、『ReDim Preserve~』で実行エラーが発生してしまいます。 原因がなぜかわかりません! そもそも、動的配列はこのような使い方は出来ないのでしょうか? Sub テスト() Dim data() As Variant Dim x As Long Dim i As Long Dim ii As Long Dim lastRow As Long Dim dataCnt As Long dataCnt = 2 For x = 2 To 5 Worksheets(x).Activate lastRow = Cells(Rows.Count, 1).End(xlUp).Row If x = 2 Then ReDim data(2 To lastRow, 3) Else ReDim Preserve data(2 To dataCnt + lastRow - 1, 3) End If For i = 2 To lastRow For ii = 1 To 3 data(dataCnt, ii) = Cells(i, ii) Next ii dataCnt = dataCnt + 1 Next i Next x End Sub どなたかご指導をよろしくお願いいたします。

  • 配列を初期化する時ってどうすればいいですか?

    Dim test() As String や Dim test As Variant で、宣言した配列を初期化する時ってどうすればいいですか? test="" test=Null test= Empty test= = Nothing は、エラーになります。

専門家に質問してみよう