• ベストアンサー

accessVBAで特定の文字列を削除

以前頼んで作ってもらったVBAを少し改造しようと思っていますが、上手くいきませんので質問します。よろしくお願いします。 csvファイルを分割するVBAを作ってもらいました。 1001,a12345678 1001,b15467863546789 1001,b25463254875698 1001,c23564879 1005,a23456753 1005,b25647565823653 1005,c26546875 1007,a23456789 1007,b23659856325632 1007,b46785215468523 1007,c12546873 というcsvファイルを 1001.csvというファイルで中身は 1001,a12345678 1001,b15467863546789 1001,b25463254875698 1001,c23564879 と 1005.csvというファイルで中身は、 1005,a23456753 1005,b25647565823653 1005,c26546875 と 1007.csvというファイルで中身は、 1007,a23456789 1007,b23659856325632 1007,b46785215468523 1007,c12546873 の3つのcsvファイルに分けます。 今回は仕様変更で、 1001.csvというファイルで中身は a12345678 b15467863546789 b25463254875698 c23564879 と 1005.csvというファイルで中身は、 a23456753 b25647565823653 c26546875 と 1007.csvというファイルで中身は、 a23456789 b23659856325632 b46785215468523 c12546873 の3つに分けなくてはならなくなりました。 今使っているVBAは Private Sub DOQUERY_Click() Dim IN_FNO As Integer Dim OUT_FNO As Integer Dim BREAK_OLD As String Dim BREAK_NEW As String Dim HEADLINE As String Dim TEXTLINE As String Dim ARY() As String Dim OUTNAME As String Dim ARYNAME() As String Dim CNT As Integer Dim MSG As String '============================================ On Error GoTo err If IsNull(InputFile) Or IsNull(OutputFile) Then Exit Sub End If If InputFile = "" Or OutputFile = "" Then MsgBox "ファイル名が正しく指定されていません。", vbCritical Exit Sub End If ラベル5.Visible = True DoEvents '読込みCSV OPEN IN_FNO = FreeFile Open InputFile For Input As #IN_FNO '見出し読込み Line Input #IN_FNO, HEADLINE$ '1レコード目読込み Line Input #IN_FNO, TEXTLINE$ '発注番号 ARY() = Split(TEXTLINE$, ",") BREAK_NEW = Replace(ARY(0), """", "") BREAK_OLD = BREAK_NEW '出力CSVファイル名作成 OUTNAME = OutputFile & BREAK_NEW & ".csv" '出力CSVファイル名保存 CNT = 1 ReDim Preserve ARYNAME(CNT) ARYNAME(CNT) = OUTNAME '出力CSV OPEN OUT_FNO = FreeFile Open OUTNAME For Output As #OUT_FNO '見出し書込み Print #IN_FNO, HEADLINE$ '1レコード目書込み Print #IN_FNO, TEXTLINE$ Do While Not EOF(IN_FNO) '次レコード目読込み Line Input #IN_FNO, TEXTLINE$ '発注番号 ARY() = Split(TEXTLINE$, ",") BREAK_NEW = Replace(ARY(0), """", "") '発注番号が変わったとき新しいCSVを開く If BREAK_OLD <> BREAK_NEW Then CNT = CNT + 1 BREAK_OLD = BREAK_NEW '旧書込みCSVをクローズ Close #OUT_FNO '新出力CSVファイル名作成 OUTNAME = OutputFile & BREAK_NEW & ".csv" '新出力CSVファイル名保存 ReDim Preserve ARYNAME(CNT) ARYNAME(CNT) = OUTNAME '新出力CSV OPEN OUT_FNO = FreeFile Open OUTNAME For Output As #OUT_FNO End If '次レコード書込み Print #OUT_FNO, TEXTLINE$ Loop '出力CSVクローズ Close #OUT_FNO '入力CSVクローズ Close #IN_FNO '出力したCSV名称一覧 Dim I As Integer For I = 1 To UBound(ARYNAME()) MSG = MSG & ARYNAME(I) & vbCrLf Next MsgBox CNT & "個のファイルに分割しました。" & vbCrLf + vbCrLf & MSG, vbInformation, "CSV分割" ラベル5.Visible = False Exit Sub err: MsgBox err.Description, vbCritical, "エラー" ラベル5.Visible = False End Sub です。 ファイル名がBREAK_NEWでそれを消せればいいと思うのですが・・・ 以上長くなりましたが、よろしくお願いします。

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

  • ベストアンサー
noname#140971
noname#140971
回答No.1

1001,a12345678-------->1001.csv 1001,b15467863546789-->1001.csv 1001,b25463254875698-->1001.csv 1001,c23564879-------->1001.csv 1005,a23456753-------->1005.csv 1005,b25647565823653-->1005.csv 1005,c26546875-------->1005.csv 1007,a23456789-------->1007.csv 1007,b23659856325632-->1007.csv 1007,b46785215468523-->1007.csv 1007,c12546873-------->1007.csv と、いう感じですかね。 Private Sub コマンド0_Click()   Dim I       As Integer   Dim N       As Integer   Dim strDatas()   As String   Dim strNewDatas  As String   Dim strNewFileName As String   Dim strNowFileName As String      strDatas() = FileReadArray("C:\Temp\Test.csv")   N = UBound(strDatas())   For I = 0 To N     If CharCount((strDatas(I)), ",") = 1 Then       strNewFileName = CutStr(strDatas(I), ",", 1)       If strNewFileName <> strNowFileName Then         If Len(strNowFileName & "") Then           FileWrite "C:\Temp\" & strNowFileName & ".csv", strNewDatas         End If         strNewDatas = CutStr(strDatas(I), ",", 2) & vbCrLf         strNowFileName = strNewFileName       Else         strNewDatas = strNewDatas & CutStr(strDatas(I), ",", 2) & vbCrLf       End If     End If   Next I   FileWrite "C:\Temp\" & strNowFileName & ".csv", strNewDatas End Sub FileSystemObject を利用すると、こんな感じになります。 多分、以下の解説を読むまでもなく理解できると思います。 strDatas() = FileReadArray("C:\Temp\Test.csv") <--- 配列に呼び込む N = UBound(strDatas())<----------------------------- 配列の数を調べる For I = 0 To N<------------------------------------- 配列をループで調査・処理 Next I If CharCount((strDatas(I)), ",") = 1 Then <-------- 呼び込んだデータが処理対象か調べる strNewFileName = CutStr(strDatas(I), ",", 1)<------- ファイルネームを切り取る If strNewFileName <> strNowFileName Then <---------- ファイル名が切り替わったら書き込み処理 Else End If FileWrite "C:\Temp\" & strNowFileName & ".csv", strNewDatas<--- 書き込み処理 strNewDatas = CutStr(strDatas(I), ",", 2) & vbCrLf <-----------書き込みデータを初期化し先頭を代入 strNewDatas = strNewDatas & CutStr(strDatas(I), ",", 2) & vbCrLf<-----書き込みデータをアペンド。 Public Function CutStr(ByVal Text As String, _             ByVal Separator As String, _             ByVal N As Integer) As String   Dim strDatas() As String      strDatas = Split("" & Separator & Text, Separator, , 0)   CutStr = strDatas(N * Abs((N <= UBound(strDatas)))) End Function Public Function CharCount(ByVal Text As String, ByVal C As String) As Integer   CharCount = Len(Text) - Len(Replace(Text, C, "")) End Function さて、FileReadArray()、FileWrite()ですが、これは長くなるので別途補足します。 先ずは、ここまで。

その他の回答 (2)

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.3

BREAK_NEWでは対処不能でしょう 変数宣言を dim ss as string, sHead() as String Dim sBreakNew() as String, sBreakOld as String ファイルの分割部分を Open InputFile For Input As #IN_FNO   '見出し読込み   Line Input #IN_FNO, ss   ' 見出しを分割   sHead = Split( ss, ",")   '1レコード目読込み   ' Line Input #IN_FNO, TEXTLINE$   Cnt = -1   OUT_FNO = -1   sBreakOld = ""   do Until Eof( IN_FNO )     line Input #IN_FNO, ss     if InStr( ss, "," ) then       ' 1レコードを分割       sBreakNew = Split( ss, "," )       sBreak(0) = Replace( sBreakNew(0), """", "" )       ' 出力ファイルの切り替えを判断       if sBreakOld <> sBreakNew(0) then         ' 出力ファイルを開いていれば閉じる         if OUT_FNO<>-1 then Close #OUT_FNO         OUT_FNO = FREEFILE         Open sBreakNew(0) & ".csv" for output as #OUT_FNO         ' 見出し出力         priint #OUT_FNO, sHead(1)         ' ファイル名更新         sBreakOld = sBreakNew(0)         cnt = cnt + 1         Redim Preserve ARYNAME(CNT)         ARYNAME( cnt ) = sBreakOld       end if       ' データの出力       Print #OUT_FNO, sBreakNew(1)     end if   Loop   ' 開いたファイルすべて閉じる   Close   MsgBox CNT & "個のファイルに分割しました。" & vbCrLf + vbCrLf & JOIN( ARYNAME, vbcrlf), vbInformation, "CSV分割" といった具合でしょう

kumahas
質問者

お礼

変数を2つに分ければ良かったんですね。 今やった限りではところどころでエラーが出て、まだ完全ではありませんが、この方法ならできそうです。 どうも有難うございました。

noname#140971
noname#140971
回答No.2

Public Function FileWrite(ByVal FileName As String, _              ByVal Text As String) As Boolean On Error GoTo Err_FileWrite   Dim fso As Object   Dim txs As Object      Set fso = CreateObject("Scripting.FIleSystemObject")   Set txs = fso.CreateTextFile(FileName, True)   txs.Write Text   FileWrite = True Exit_FileWrite:   Exit Function Err_FileWrite:   MsgBox Err.Description & "(FileWrite)", vbExclamation, " 関数エラーメッセージ"   Resume Exit_FileWrite End Function Public Function FileReadArray(ByVal FileName As String) As String() On Error GoTo Err_FileReadArray   Dim fso As Object   Dim strTexts() As String      Set fso = CreateObject("Scripting.FIleSystemObject")   strTexts() = Split(fso.OpenTextFile(FileName).ReadAll, vbCrLf) Exit_FileReadArray:   FileReadArray = strTexts()   Exit Function Err_FileReadArray:   MsgBox Err.Description & "(FileReadArray)", vbExclamation, " 関数エラーメッセージ"   strTexts() = Split("")   Resume Exit_FileReadArray End Function ================== 質問自体への回答 ================== 処理全体の流れは、全く同じことです。 ですから、先の回答も質問者のやり方で書けます。 ただ、それぞれが多少長くなるだけです。

kumahas
質問者

お礼

CharCountとCutStrでもコンパイルエラーが出ましたが、教えてgooの中から拾えましたので無事分割できました。 accessはマクロが中心でVBAを自分でどうこうすることはほとんど無く、知り合いに作ってもらっていました。 これを機会に本格的に勉強しようかと思います。 有難うございました。

関連するQ&A

  • VBAで任意のフォルダ内のファイルの特定の文字列を

    お世話になります。今、Excelを使用しVBAで任意のフォルダ内に含まれるファイル(txt形式ですが拡張子はありません)から、特定のA~Bの部分の文字列のみを抜き出し、ExcelのSheetに出力させるというVBAを作成しようと考えています。また、A~Bで抽出した文字列内に”空白”が含まれる場合、その空白でセルを隔てるという処理を加えたいです。 また、それらとは別に任意のフォルダ内に含まれるファイルのファイル名のみを抽出し、Excelに出力するというVBAも作ろうと考えています。 私自身、これまでExcelでは関数を使うのが精一杯でVBAの勉強すらしてきませんでしたので、だいぶ困窮しております。 どなたか、VBAについて詳しい方、ご教授いただけたら幸いです。 以下は、参考までに、特定のフォルダ内に含まれるファイルをSheetに出力するVBAになります。 ここからさらに、任意の文字列を検索し、抽出し、出力する機能と、また空白部分でセルを分ける機能、またファイル名一覧を抽出する機能を加えていきたい所存です。 どなたか、お力添えの程何卒よろしくお願い致します。 Sub GetAllFile() Dim buf As String, tmp As Variant, cnt As Long, i As Long Dim myFol As String, myFile As String Dim fNo As Integer, myCol As Long With Application.FileDialog(msoFileDialogFolderPicker) .Title = "*** 対象フォルダを選択し、[OK]をクリック ***" .InitialFileName = "C:\" If .Show = True Then myFol = .SelectedItems(1) End If End With myFile = Dir(myFol & "\*") myCol = 0 Do While myFile <> "" fNo = FreeFile Open myFol & "\" & myFile For Input As #fNo Do Until EOF(fNo) Line Input #fNo, buf tmp = Split(buf, ",") cnt = cnt + 1 For i = 1 To UBound(tmp) + 1 Cells(cnt, i + myCol) = tmp(i - 1) Next i Loop Close #fNo myFile = Dir() myCol = myCol + 4 cnt = 0 Loop End Sub 上記、VBAは動作はしましたが、やはりフォルダ内のファイル数の数により、途中でフリーズしてしまう事もありました。ご教授の程、何卒よろしくお願い致します。

  • 文字列を特定文字で分割したい

    はじめまして。宜しくお願いします。 現在Access2002のVBAをつかってタイトルのようなことを実現したいと思っています。 Dim a As String Dim b As String という二つの変数を用意して 「C:\Documents and Settings\デスクトップ\test.csv」という文字列が与えられているとき 変数aには「test.csv」を、変数bには「C:\Documents and Settings\デスクトップ\」を 格納しようとしています。 スマートなやり方がわからず、 文字列の右から一文字ずつ比較して行き、何文字目に「¥」が出てくるかをカウントして、right関数とleft関数で分割を行っています。 このような処理を行う場合、なにか適した関数があると思い探しているのですが、 なかなか見つからず、行き詰っています。(そのような関数があるのかも分からず・・) もしもなにかお気づきの方が居られましたら、ご教授宜しくお願いします。

  • 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

  • VB6で配列を文字列に変換する方法?

    VisualBasic6を使っております。 Dim ary() As Byte Dim s as String 配列を文字列に変換したり、文字列を配列にしたいのですが どのようにすれば良いのでしょうか?

  • Generic.Listに1次元配列の配列を格納したい(VB2005)

    VB2005の質問です。 変数ghogeにString型の1次元配列の配列を格納したいと考えています。 ----------------------------------------------- 'a) Dim hoge()() As string = _       {New string() {"a1", "b1", "c1"}, _       New string() {"a2", "b2", "c2"}, _       New string() {"a3", "b3", "c3"}} Dim ghoge As New Generic.List(of )   'b) MessageBox.Show(ghoge(1)(1))      ' "b2"と表示したい ----------------------------------------------- 質問内容は、(a)を(b)の初期値として設定するにはどのようにすればよいか、ということです。 (b)がGeneric.ListでなくArrayListの場合だと、   Dim ghoge As New ArrayList(hoge) でhoge配列を格納できますが、Generic.Listの場合はどのような構文にすればよいでしょうか。 現在は、下記のような処理でghogeに値を格納しています。 ------------------------------------------------------------ Dim ghoge As New Generic.List(Of Generic.List(Of String)) Dim aryhoge1 As New Generic.List(Of String)(New String() {"a1", "b1", "c1"}) Dim aryhoge2 As New Generic.List(Of String)(New String() {"a2", "b2", "c2"}) gary_hoge.Add(ary_hoge1) gary_hoge.Add(ary_hoge2) MessageBox.Show(gary_hoge(1)(1))    ' "b2"と表示される ------------------------------------------------------------ どうぞよろしくお願い致します。

  • VBA での文字列編集

    すみません、VBA初心者であまり調べる時間がないので質問させて頂きます。 Dim strFileName As String Dim strChk1 As String Dim strChk2 As String strFileName には "20070703_TEST001_DATA.csv" の文字列のデータが 格納されているとします。 この strFileName を編集して strChk1 には "20070703" strChk2 には "TEST001" がセットされるようにしたいのですが。。。 どのようにプログラムを書くのが一番いいのでしょうか? よろしくお願いします。

  • ExcelのVBAでブックを保存

    住所録Aと住所録Bがあります。 AとBを比較して、差異をを別ファイルに出力しようとしています。 比較元となるファイルは、AでもBでもかまいません。 比較、判定、ファイルへの出力部分は、省略していますが、保存 する場合は、どこに行うのがよいのですか bookですか。sheetですか。 両方で、SaveAsができまが、使い分けがあるのでしょうか。 どのように使い分けするのでしょうか。 書き方、使い方のおかしいところを指摘して頂くとありがたい です。 --------------------------------------------------------------------------------------------------- Option Explicit Sub test() Dim ret As Integer Dim row1 As Long Dim col1 As Long Dim row2 As Long Dim col2 As Long Dim myRtn As Boolean Dim fno1 As String Dim fno2 As String Dim OutBook As New Workbook Dim OutSheet As New Worksheet Dim OutFileName As String Dim cnt As Integer Dim I As Integer ret = MsgBox("処理を開始します。" + Chr(13) + Chr(10) + "よろしいですか。?", _ vbYesNo + vbQuestion) If ret = vbNo Then End End If myRtn = Application.Dialogs(xlDialogOpen).Show If myRtn = False Then MsgBox "[キャンセル]が選択されました" & vbCr & _ "処理を終了します" Exit Sub End If fno1 = Application.ActiveWorkbook.Name myRtn = Application.Dialogs(xlDialogOpen).Show If myRtn = False Then MsgBox "[キャンセル]が選択されました" & vbCr & _ "処理を終了します" Exit Sub End If fno2 = Application.ActiveWorkbook.Name Set OutBook = Workbooks.Add Set OutSheet = ActiveSheet OutBook.Worksheets(1).Name = "テスト" OutFileName = "テスト.xls" With Application.Workbooks(fno1).Worksheets(1) row1 = 1 col1 = 1 cnt = 1 Do While .Cells(row1, 1) <> "" 処理 (省略) Loop End With MsgBox "処理が終了しました。", vbOKOnly + vbInformation, "確認" Application.Workbooks(fno1).Close Application.Workbooks(fno2).Close OutSheet.SaveAs Filename:=OutFileName OutBook.SaveAs Filename:=OutFileName OutBook.Close End Sub --------------------------------------------------------------------------------------------------- OutSheet.SaveAs Filename:=OutFileName or OutBook.SaveAs Filename:=OutFileName のどちらでも保存ができます。 また、書き方、使い方のおかしいところを指摘して頂くとありがたいです。

  • For Each ~ .split(vbCrLf)の中で条件分岐

    VB.NETでテキストファイルを読み込み、行頭が指定の文字列だったら処理をしたいです。 下記のような感じ(だいぶ端折ってますが)でやってみましたがうまくいきません。 Dim sr As New System.IO.StreamReader( テキストファイル名 , System.Text.Encoding.GetEncoding("Shift-JIS")) Dim Buffer As String = sr.ReadToEnd '行ごとに分割して判定 For Each TextLine as String In Buffer.Split(vbCrLf)   MsgBox(TextLine)   If TextLine Like "○○○*" Then     '実行したい処理   End IF NEXT メッセージボックスの表示では正常に1行ずつ取り出せていますがIfの判定ができません。 このままでは文字列として判定の条件には使えないのでしょうか?

  • エクセルの列削除がうまくいかない。

    CSV変換データの不要な列を削除しようとしているのですが、思うような動作しません。 CSV変換マクロを起動と同時にA,B,E,F,O,P,Q,R列を削除しようとしているのですが、うまくいかない。 教えていただけないでしょうか。 添付データは元のファイルです。 Option Explicit Sub EasyCopyCSV() Dim CSV_filename As Variant, target As Variant Dim CSV_SheetName As Variant Dim FileCount As Long Dim kk As Long CSV_filename = Application.GetOpenFilename(filefilter:="CSVファイル(*.csv;*.prn),*.csv;*.prn", MultiSelect:=True) If IsArray(CSV_filename) Then Else MsgBox "キャンセルされました" Exit Sub End If FileCount = UBound(CSV_filename) '配列のサイズからファイル数を調べる For kk = 1 To FileCount 'ファイル数カウンタ初期化しファイル数分カウンタを回す Workbooks.Open CSV_filename(kk) 'ファイルを開く CSV_SheetName = Worksheets(1).Name '開いたシートの名前=ファイル名を取得 Sheets(CSV_SheetName).Move Before:=ThisWorkbook.Sheets(1) Next '不要列を削除 With ActiveSheet .Range(.Columns(1), .Columns(2)).Delete Shift:=xlShiftToLeft .Range(.Columns(5), .Columns(6)).Delete Shift:=xlShiftToLeft .Range(.Columns(15), .Columns(18)).Delete Shift:=xlShiftToLeft End With End Sub

  • Functionでの戻り値のとり方

    こんばんわ。 以下のように、Functionで引数に配列を指定して、戻り値も配列で取得したいのですが、方法としては以下のようにしかできないのでしょうか? ------------------------- '配列を宣言 dim Ary() as string dim AryRet() as string '戻り値の配列 Call Get_Ary(Ary(),AryRet()) ------------------------- Function Get_Ary(Ary() as string , AryRet() as string) 'Ary()を参照して、AryRet()を取得する End Function という風に書いているのですが、Functionのところを以下のように 書くのは無理でしょうか? うまく取れないというのはやっぱ無理なのかな・・ ------------------------- '配列を宣言 dim Ary() as string dim AryRet() as string '戻り値の配列 AryRet() = Get_Ary(Ary()) Function Get_Ary(Ary() as string) As string 'Ary()を参照して、AryRet()を取得する 'それを関数の戻り値とする Get_Ary = AryRet(index) End Function このように書くと、配列の最後のインデックスの値だけ取れてしまう ようなんですが、、やっぱ配列で返すというのは上記のやり方でないと 無理なのでしょうか? 詳しい方ご教示願います。

専門家に質問してみよう