Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


6942 / 13646 ツリー ←次へ | 前へ→

【41852】csvファイルにて 質問(煮詰まった) 06/8/24(木) 10:12 質問[未読]
【41853】Re:csvファイルにて Jaka 06/8/24(木) 10:35 発言[未読]
【41872】Re:csvファイルにて Hirofumi 06/8/24(木) 19:08 回答[未読]
【41893】Re:csvファイルにて 質問(煮詰まった) 06/8/25(金) 11:30 お礼[未読]
【42112】Re:csvファイルにて 質問(煮詰まった) 06/9/1(金) 13:28 質問[未読]
【42120】Re:csvファイルにて Hirofumi 06/9/1(金) 19:56 回答[未読]
【42204】Re:csvファイルにて 質問(煮詰まった) 06/9/4(月) 10:10 お礼[未読]
【42118】Re:csvファイルにて りん 06/9/1(金) 15:37 回答[未読]

【41852】csvファイルにて
質問  質問(煮詰まった)  - 06/8/24(木) 10:12 -

引用なし
パスワード
   1点教えて下さい。
csvファイルの変換の処理です。

csvのファイルをxls形式に変換しています。

"AAAA,BBBB",2,3, のようなケースで""を除いて
,(カンマ)の箇所まで1項目として処理しているのですが
項目中の,の場合にうまく変換できません。
対応方法を教えて下さい。

以下の変換はWebで検索してそのまま利用している処理になります。
シングルコーテーション、ダブルコーテーションで囲まれている場合は両端文字を取り除く処理で,も条件にいれてみたのですがうまく行かなくなった
ので教えて下さい。

最悪、項目中のカンマは別の文字に置き換えてもかまわないのですが・・


' FreeFile値の取得(以降この値で入出力する)
  intFF = FreeFile
  ' 指定ファイルをOPEN(入力モード)
  Open strFILENAME For Input As #intFF
  GYO = 1
  ' ファイルのEOF(End of File)まで繰り返す
  Do Until EOF(intFF)
    ' レコード件数カウンタの加算
    lngREC = lngREC + 1
    xlAPP.StatusBar = "読み込み中です....(" & lngREC & "レコード目)"
    ' 行単位にレコードを読み込む
    Line Input #intFF, strREC                   ' 1.

    ' LineInputより自分で半角カンマを探しCSV→項目分割させる
    POS1 = 1
    IX1 = 0
    ReDim X(IX1)        ' 配列を初期化
    Do While POS1 <= Len(strREC)                  ' 2.
      POS2 = InStr(POS1, strREC, ",", vbTextCompare)       ' 3.
      If POS2 < POS1 Then
        POS2 = Len(strREC) + 1
      End If
      ReDim Preserve X(IX1)  ' 配列要素数を再設定
      X(IX1) = Trim$(Mid$(strREC, POS1, POS2 - POS1))      ' 4.
      ' シングルコーテーション、ダブルコーテーションで囲まれている場合は
      ' 両端文字を取り除く
      If (((Left$(X(IX1), 1) = """") And (Right$(X(IX1), 1) = """")) Or _
        ((Left$(X(IX1), 1) = "'") And (Right$(X(IX1), 1) = "'"))) Then ' 5.
        X(IX1) = Trim$(Mid$(X(IX1), 2, Len(X(IX1)) - 2))
      End If
      POS1 = POS2 + 1
      IX1 = IX1 + 1
    Loop

    ' 行を加算しレコード内容を表示(先頭は2行目)
    GYO = GYO + 1
    If IX1 >= 1 Then
      Range(Cells(GYO, 1), Cells(GYO, IX1)).Value = X  ' 配列渡し 6.
    End If
  Loop
  ' 指定ファイルをCLOSE
  Close #intFF
  xlAPP.StatusBar = False
  ' 終了の表示
  MsgBox "ファイル読み込みが完了しました。" & vbCr & _
    "レコード件数=" & lngREC & "件", vbInformation, cnsTITLE

【41853】Re:csvファイルにて
発言  Jaka  - 06/8/24(木) 10:35 -

引用なし
パスワード
   Line Input #intFF, strREC  

Input #intFF, strREC
にすれば、""を一くくりのデータと読み込んでくれます。
ただ、""内の半角スペース等は、そのまま出ますが、
123,  aaaa  , bbbb
等の半角スペースは、削られます。
後、Variantでそのまま読み込むと不具合がでる場合があったりします。
(過去ログにあります。)
                                   

【41872】Re:csvファイルにて
回答  Hirofumi  - 06/8/24(木) 19:08 -

引用なし
パスワード
   チョット長いけどこんなので読めると思います
シングルクォーテーション、ダブルクォテーションが混在する事は、
無いと思いますのでこのコードでは、ダブルクォテーションの場合のみの処理をしています

Option Explicit

Public Sub DataRead()

  Dim vntFileName As Variant
  Dim lngRow As Long
  Dim rngResult As Range
  Dim strProm As String

  '出力先頭セル位置を設定(基準セル位置)
  Set rngResult = ActiveSheet.Cells(1, "A")

  '読み込むファイルを取得
  If Not GetReadFile(vntFileName, ThisWorkbook.Path) Then
    strProm = "マクロがキャンセルされました"
    GoTo Wayout
  End If

  '画面更新を停止
'  Application.ScreenUpdating = False

  '出力行初期値(基準セル位置からの行Offset)
  lngRow = 0

  'データの読み込み
  CSVRead vntFileName, rngResult, lngRow

  strProm = "処理が完了しました"

Wayout:

  Set rngResult = Nothing

  '画面更新を再開
'  Application.ScreenUpdating = True

  MsgBox strProm, vbInformation

End Sub

Private Sub CSVRead(ByVal strFileName As String, _
          ByRef rngWrite As Range, _
          Optional ByRef lngRow As Long = 1, _
          Optional strDelim As String = ",")

  Dim dfn As Integer
  Dim vntField As Variant
  Dim strBuff As String
  Dim blnMulti As Boolean
  Dim strREC As String

  'ファイルをOpen
  dfn = FreeFile
  Open strFileName For Input As dfn

  Do Until EOF(dfn)
    '1行読み込み
    Line Input #dfn, strBuff
    '論理レコードに物理レコードを追加
    strREC = strREC & strBuff
    '論理レコードをフィールドに分割
    vntField = SplitCsv(strREC, strDelim, , , blnMulti)
    'フィールド内で改行が有る場合
    If Not blnMulti Then
      With rngWrite.Offset(lngRow)
        With .Resize(, UBound(vntField) + 1)
          '出力範囲を文字列に設定
'          .NumberFormat = "@"
          'データを出力
          .Value = vntField
        End With
      End With
      '出力行をインクリメント
      lngRow = lngRow + 1
      strREC = ""
    Else
      'セル内改行として残す場合
      strREC = strREC & vbLf
    End If
  Loop

  Close #dfn

End Sub

Public Function SplitCsv(ByVal strLine As String, _
            Optional strDelimiter As String = ",", _
            Optional strQuote As String = """", _
            Optional strRet As String = vbCrLf, _
            Optional blnMulti As Boolean) As Variant

  Dim i As Long
  Dim lngDPos As Long
  Dim vntData() As Variant
  Dim lngStart As Long
  Dim vntField As Variant
  Dim lngLength As Long

  i = 0
  lngStart = 1
  lngLength = Len(strLine)
  blnMulti = False
  Do
    ReDim Preserve vntData(i)
    If Mid$(strLine, lngStart, 1) <> strQuote Then
      lngDPos = InStr(lngStart, strLine, _
            strDelimiter, vbBinaryCompare)
      If lngDPos > 0 Then
        vntField = Mid$(strLine, lngStart, _
                  lngDPos - lngStart)
        If lngDPos = lngLength Then
          ReDim Preserve vntData(i + 1)
        End If
        lngStart = lngDPos + 1
      Else
        vntField = Mid$(strLine, lngStart)
        lngStart = lngLength + 1
      End If
    Else
      lngStart = lngStart + 1
      Do
        lngDPos = InStr(lngStart, strLine, _
                strQuote, vbBinaryCompare)
        If lngDPos > 0 Then
          vntField = vntField & Mid$(strLine, _
                lngStart, lngDPos - lngStart)
          lngStart = lngDPos + 1
          Select Case Mid$(strLine, lngStart, 1)
            Case ""
              Exit Do
            Case strDelimiter
              lngStart = lngStart + 1
              Exit Do
            Case strQuote
              lngStart = lngStart + 1
              vntField = vntField & strQuote
          End Select
        Else
          blnMulti = True
          vntField = Mid$(strLine, lngStart)
          lngStart = lngLength + 1
          Exit Do
        End If
      Loop
    End If
    vntData(i) = vntField
    vntField = Empty
    i = i + 1
  Loop Until lngLength < lngStart

  SplitCsv = vntData()

End Function

Public Function GetReadFile(vntFileNames As Variant, _
            Optional strFilePath As String, _
            Optional blnMultiSel As Boolean _
                    = False) As Boolean

  Dim strFilter As String

  'フィルタ文字列を作成
  strFilter = "CSV File (*.csv),*.csv," _
        & "Text File (*.txt),*.txt," _
        & "CSV and Text (*.csv; *.txt),*.csv;*.txt," _
        & "全て (*.*),*.*"
  '読み込むファイルの有るフォルダを指定
  If strFilePath <> "" Then
    'ファイルを開くダイアログ表示ホルダに移動
    ChDrive Left(strFilePath, 1)
    ChDir strFilePath
  End If
  'もし、ディフォルトのファイル名が有る場合
  If vntFileNames <> "" Then
    SendKeys vntFileNames & "{TAB}", False
  End If
  '「ファイルを開く」ダイアログを表示
  vntFileNames _
      = Application.GetOpenFilename(strFilter, 1, , , blnMultiSel)
  If VarType(vntFileNames) = vbBoolean Then
    Exit Function
  End If

  GetReadFile = True

End Function

【41893】Re:csvファイルにて
お礼  質問(煮詰まった)  - 06/8/25(金) 11:30 -

引用なし
パスワード
   助かりました

【42112】Re:csvファイルにて
質問  質問(煮詰まった)  - 06/9/1(金) 13:28 -

引用なし
パスワード
   1点教えて下さい。

csvのデータ中に前0を含むデータがうまく変換できません。
前0が除かれて処理されます。

どの箇所を修正すればいいのか教えて下さい。


尚、更新しようとしているシートは文字列で指定
しています。

【42118】Re:csvファイルにて
回答  りん E-MAIL  - 06/9/1(金) 15:37 -

引用なし
パスワード
   質問(煮詰まった) さん、こんにちわ。

別解になりますが。
一括で読み込み、区切位置の指定で分割しています。
Sub test()
  '|"AAAA,BBBB",2,3,01|→|AAAA,BBBB|2|3|01|
  
  Dim AA As String, RR As Long, LL As Integer, Lmax As Integer
  With Application.ActiveSheet
    .Columns(1).NumberFormat = "@"
    Open "test.csv" For Input As #1
     Do Until EOF(1)
      Line Input #1, AA
      RR = RR + 1
      .Cells(RR, 1).Value = AA
      LL = Len(AA) - Len(Application.WorksheetFunction.Substitute(AA, ",", "")) 'おおよそのカンマの数
      If Lmax < LL Then Lmax = LL
     Loop
    Close #1
    ReDim fidt(1 To Lmax, 1 To 2)
    For LL = 1 To Lmax
      fidt(LL, 1) = LL '列番号
      fidt(LL, 2) = 2 '文字列
    Next
    .Columns(1).TextToColumns DataType:=xlDelimited, Comma:=True, _
    FieldInfo:=fidt()
  End With
  Erase fidt
End Sub

こんな感じです

【42120】Re:csvファイルにて
回答  Hirofumi  - 06/9/1(金) 19:56 -

引用なし
パスワード
   >1点教えて下さい。
>
>csvのデータ中に前0を含むデータがうまく変換できません。
>前0が除かれて処理されます。
>
>どの箇所を修正すればいいのか教えて下さい。
>
>
>尚、更新しようとしているシートは文字列で指定
>しています

此れは、読み込むコードの問題ではなく?(セルへの代入は、0が付いた形で代入しています)
Excelが数値として受け取れる物は、勝手に数値にしてしまう事によります

此れを、回避する場合は、予め読み込む列のセル書式を文字列にして置く方法が有ります
また、全てを文字列で読み込んで善いのなら、「Private Sub CSVRead」の中で
以下の部分のコメントアウトを活かせば、全て文字列とし読み込みます
(範囲に代入する前に、代入する範囲のセル書式を文字列に設定しています

    'フィールド内で改行が有る場合
    If Not blnMulti Then
      With rngWrite.Offset(lngRow)
        With .Resize(, UBound(vntField) + 1)
          '出力範囲を文字列に設定
          .NumberFormat = "@"    '★この行を活かす
          'データを出力
          .Value = vntField
        End With
      End With

【42204】Re:csvファイルにて
お礼  質問(煮詰まった)  - 06/9/4(月) 10:10 -

引用なし
パスワード
   助かりましたうまく行きました。

6942 / 13646 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free