新生活を充実させるための「こだわり」を取材!!

VB6でCSVファイルを読み込みたいのですが、
以下のような項目だと、1項目として読み込むことができません。

例) AAA,"BBB,CCC,"" """,DDD

"BBB,CCC,"" """ を1項目として読み込みたいのですが
ダブルコーテーションの括りの中に、更にダブルコーテーションがあると
うまくいかないみたいです。
何か方法がありますでしょうか?


Open DownLoadFile For Input As #1 Len = 32000
Input #1, rec
Do Until EOF(1)
処理1

Loop
close #1

教えて!goo グレード

A 回答 (6件)

>出力フォーマットを変更する事はできないので、


やはり処理を組み込むしかないようですね。

参考になればよいのですが、サンプルを作成しました。
ExcelのVBAで動いたので多分大丈夫だとは思うのですが、、、

ダメっぽかったらそちらで修正して^^;

Option Explicit

Public Const DEF_CHR34   As String = """"  'ダブルコーテーション
Public Const DEF_SPLIT_CHAR As String = ","   '区切り文字

Sub Main()
  Dim l_strバッファ    As String
  Dim l_str一行      As String
  Dim l_strAryバッファ() As String
  Dim i          As Integer
  Dim l_strAry一行()   As String
  
  'ファイルを一気に読み込む
  l_strバッファ = ファイル読込み("C:\test.csv")
  
  '改行コードで配列化を行う
  l_strAryバッファ = Split(l_strバッファ, vbCrLf)
  
  '改行数のループ処理を行う
  For i = LBound(l_strAryバッファ) To UBound(l_strAryバッファ)
    l_str一行 = l_strAryバッファ(i)
    Debug.Print l_str一行
    
    '文字が存在していなければ、ループを抜ける
    If RTrim$(l_str一行) = "" Then
      MsgBox i + 1 & "行目が空データなので、ループをぬける"
      Stop
      Exit For
    End If
    
    Stop
    '一行を区切り文字で配列化する
    If Not 変換_ライン_配列(l_str一行, l_strAry一行, DEF_SPLIT_CHAR) Then
      MsgBox "えらー終了"
      Stop
      Exit For
    End If
    Stop
  Next i
  
End Sub


Public Function ファイル読込み(ByVal p_strファイル名 As String) As String
  Dim intFile   As Integer
  Dim lngLen   As Long
  Dim bytBuff()  As Byte
  
  intFile = FreeFile
  lngLen = FileLen(p_strファイル名)
  
  If lngLen = 0 Then
    Exit Function
  End If
  
  ReDim bytBuff(0 To lngLen - 1)
  Open p_strファイル名 For Binary Access Read As intFile
  Get intFile, , bytBuff
  Close intFile
  
  ファイル読込み = StrConv(bytBuff, vbUnicode)
End Function


'文字列を、指定の区切りキャラで、配列化を行う
Public Function 変換_ライン_配列( _
  ByVal p_str一行 As String, _
  ByRef p_strAry一行() As String, _
  Optional ByVal p_str区切 As String = "," _
) As Boolean
  Dim l_bln実行結果    As Boolean
  Dim l_strAry区切()   As String
  Dim l_str文字列     As String
  Dim i          As Integer
  Dim l_intカウント取得数 As Integer
  Dim l_strAry返却()   As String
  
  l_bln実行結果 = True
  
  '区切り文字で配列化する
  l_strAry区切 = Split(p_str一行, p_str区切)
  
  '配列要素数でループを行う
  For i = LBound(l_strAry区切) To UBound(l_strAry区切)
    '取得する
    If Not 補正取得(l_strAry区切, i, l_str文字列, p_str区切) Then
      'エラー処理
      l_bln実行結果 = False
      Exit For
    End If
    
    '取得した文字列を、配列として記憶する
    ReDim Preserve l_strAry返却(l_intカウント取得数)
    l_strAry返却(l_intカウント取得数) = l_str文字列
    
    l_intカウント取得数 = l_intカウント取得数 + 1
  Next i
  
  '記憶した配列を返却する
  p_strAry一行 = l_strAry返却

  '取得結果のステータスを返却する
  変換_ライン_配列 = l_bln実行結果
End Function

Private Function 補正取得( _
    ByRef p_strAry区切() As String, _
    ByRef p_int開始位置 As Integer, _
    ByRef p_str取得文字 As String, _
    ByVal p_str区切 As String _
) As Boolean
  Dim l_bln実行結果    As Boolean
  Dim i          As Integer
  Dim l_str文字      As String
  Dim l_strAryChr34()   As String
  Dim l_intカウントChr34 As Integer
  Dim l_str文字連結    As String
  
  
  l_str文字 = p_strAry区切(p_int開始位置)
  
  If Left$(l_str文字, 1) = DEF_CHR34 Then
    'ダブルコーテーションで文字列が始まる場合
    For i = p_int開始位置 To UBound(p_strAry区切)
      l_str文字 = p_strAry区切(i)
      
      '初回のループでなければ、区切りキャラを追加する
      If i <> p_int開始位置 Then
        l_str文字連結 = l_str文字連結 & p_str区切
      End If
      '文字列の連結を行う
      l_str文字連結 = l_str文字連結 & l_str文字
      
      '内部に存在するダブルコーテーションの数を取得する
      l_strAryChr34 = Split(l_str文字, DEF_CHR34)
      l_intカウントChr34 = l_intカウントChr34 + UBound(l_strAryChr34)
      
      '一番右の文字がダブルコーテーションである 且つ ダブルコーテーションのカウントが偶数である
      If (Right$(l_str文字, 1) = DEF_CHR34) And ((l_intカウントChr34 Mod 2) = 0) Then
        '先頭と最後のダブルコーテーションを抹消
        p_str取得文字 = Mid$(l_str文字連結, 2, Len(l_str文字連結) - 2)
        
        '呼び出し元のループカウンタのポジションを進める
        p_int開始位置 = i
        
        '正常処理であることを通知
        l_bln実行結果 = True
        Exit For
      End If
    Next i
    
  Else
    'ダブルコーテーションで文字列が始まらない場合
    '取得した値をそのままセット
    p_str取得文字 = l_str文字
    
    '正常処理であることを通知
    l_bln実行結果 = True
  End If
  
  '取得結果のステータスを返却する
  補正取得 = l_bln実行結果
End Function
    • good
    • 0

もう一つのサンプルを作成しました。


OLEDBドライバ+ADOでのサンプルです。

OLEDBがテキストに対応していたら、テキストをデータセットとして取得することも出来ます。

おそらくテキストの拡張子が
txt
csv
tab
asc
であれば可能だと思います。


Public Const DEF_CHR34   As String = """"  'ダブルコーテーション

Sub テスト()
  Dim l_adoRec  As Object  'ADODB.Recordset
  Dim l_adoFld  As Object  'ADODB.Field
  Dim i      As Integer
  Dim l_intCount As Integer
  
  Set l_adoRec = GetAdoRecordSet("C:\test.asc", False)
  Do Until l_adoRec.EOF
    l_intCount = l_intCount + 1
    If IsNull(l_adoRec.Fields(0)) Then
      Debug.Print l_intCount & "件目の先頭が未設定なので、処理を抜けました"
      Exit Do
    End If
  
    Debug.Print String(15, "-")
    Debug.Print l_intCount & "件目"
    Debug.Print String(15, "-")
    For Each l_adoFld In l_adoRec.Fields
      'ADOの仕様で、ダブルコーテーション2個は1個に置き換えられるので、それを戻す処理も同時に行う
      Debug.Print Replace(l_adoFld.Value, DEF_CHR34, String(2, DEF_CHR34))
    Next
    l_adoRec.MoveNext
  Loop
End Sub

Private Function GetAdoRecordSet(ByVal p_strPath As String, p_bln先頭がヘッダ項目 As Boolean) As Object
  Dim l_adoCnn  As Object  'ADODB.Connection
  Dim l_strCnn  As String
  Dim l_strSQL  As String
  Dim l_fsoFile  As Object  'Scripting.File
  Dim l_strヘッダオプション  As String
  
  'テキストの先頭がヘッダを含むかどうかの設定
  If p_bln先頭がヘッダ項目 Then
    l_strヘッダオプション = "YES"
  Else
    l_strヘッダオプション = "NO"
  End If
  
  
  'ファイルを取得する
  Set l_fsoFile = GetFsoFileObject(p_strPath)
  
  'コネクションオープン
  Set l_adoCnn = CreateObject("ADODB.Connection")
  l_strCnn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" _
        & l_fsoFile.ParentFolder.Path _
        & ";Extended Properties=""Text;HDR=" & l_strヘッダオプション & """"
  l_adoCnn.Open l_strCnn
  
  'レコードセットを取得
  l_strSQL = "SELECT * FROM [" & l_fsoFile.Name & "]"
  Set GetAdoRecordSet = l_adoCnn.Execute(l_strSQL)
End Function

Private Function GetFsoFileObject(ByVal p_strPath As String) As Object
  Set GetFsoFileObject = CreateObject("Scripting.FileSystemObject").GetFile(p_strPath)
End Function
    • good
    • 0

カンマの点から、Input#のステートメントに頼れないと思うので


Line Input #ステートメントを使って、1行全部を文字列として受け取り、内容にしたがって、後はしたいように、切り出しを、ロジックを工夫してコーディングするより他ないと思う。
そのロジックは、規則性があるのかないのかも、質問に内容が掲示できてないので、判りません。
最悪Input¥ステートメトで指定文字数分受け取り、レコード分解も
自力でになるかも。
    • good
    • 0

どんぴしゃ。

とはいかないけど、
エクセルで開いて、セルを読んだら?

規則性はないんでしょ。
    • good
    • 0

例) AAA,"BBB,CCC,"" """,DDD


を読み込んだときどのような結果を希望しているのでしょうか?
2つ連続するダブルクォーテーションはデータのダブルクォーテーションとみなす
というルールなら、左側から1文字ずつ読んで
項目1=AAA
項目2=BBB,CCC," "
項目3=DDD
ということになると思います。

項目分けは自力で行うしかないでしょう。
Open DownLoadFile For Input As #1 Len = 32000
Do Until EOF(1)
 Line Input #1, rec
 recを先頭から1文字ずつ見て項目分けする処理
 処理1
Loop
close #1
    • good
    • 0

解決策ではありませんが、、、、



このCSVのフォーマットは、もう確定ですか?


というのは、
・「カンマ」区切り
・文字列を「ダブルコーテーション」で囲む
という仕様のCSVであれば、CSVのデータは
・「カンマ」
・「ダブルコーテーション」
は禁則文字にすることが前提だと思います。


しかし、データとして存在しているからこそこういう問題が発生していると思うので、、、

※出力フォーマットとして
・「TAB」区切りを利用する
・文字列を""で囲む事をしない
というルールに変更が可能であれば、そちらをお勧めしたいです。
    • good
    • 0
この回答へのお礼

ありがとうございます。

解決策はありませんか。。。

でも、出力フォーマットを変更する事はできないので、
何か手を考えなければいけない・・・。

お礼日時:2006/05/17 19:43

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


人気Q&Aランキング