• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:CSVファイルの「”」について)

CSVファイルの「"」について

このQ&Aのポイント
  • VB6でCSVファイルを読み込む際に、ダブルコーテーションの扱いに問題が生じることがあります。例えば、ダブルコーテーションの中にさらにダブルコーテーションが含まれている場合、1つの項目として正しく読み込むことができません。
  • この問題を解決する方法はありますか?ダブルコーテーションが入った項目を正しく読み込む方法を教えてください。
  • VB6のCSVファイル読み込みにおいて、ダブルコーテーションの扱いについて困っています。ダブルコーテーションの中にさらにダブルコーテーションがある場合、正しく読み込むことができません。解決策を教えてください。

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

  • ベストアンサー
回答No.5

>出力フォーマットを変更する事はできないので、 やはり処理を組み込むしかないようですね。 参考になればよいのですが、サンプルを作成しました。 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

その他の回答 (5)

回答No.6

もう一つのサンプルを作成しました。 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

  • imogasi
  • ベストアンサー率27% (4737/17069)
回答No.4

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

回答No.3

どんぴしゃ。とはいかないけど、 エクセルで開いて、セルを読んだら? 規則性はないんでしょ。

回答No.2

例) 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

回答No.1

解決策ではありませんが、、、、 このCSVのフォーマットは、もう確定ですか? というのは、 ・「カンマ」区切り ・文字列を「ダブルコーテーション」で囲む という仕様のCSVであれば、CSVのデータは ・「カンマ」 ・「ダブルコーテーション」 は禁則文字にすることが前提だと思います。 しかし、データとして存在しているからこそこういう問題が発生していると思うので、、、 ※出力フォーマットとして ・「TAB」区切りを利用する ・文字列を""で囲む事をしない というルールに変更が可能であれば、そちらをお勧めしたいです。

ddaaii
質問者

お礼

ありがとうございます。 解決策はありませんか。。。 でも、出力フォーマットを変更する事はできないので、 何か手を考えなければいけない・・・。

関連するQ&A