[リストへもどる]   [VBレスキュー(花ちゃん)]
一括表示

投稿時間:2007/03/06(Tue) 17:11
投稿者名:べた
Eメール:
URL :
タイトル:
カンマ区切りのCSVファイルの読み込み
カンマ区切りのCSV形式のファイルから読み込みを行っています。
複数のテキストデータを読み込むため、読み込むテキストデータ分
の変数を設定しているのですが、

Input #1, buff1, buff2, buff3, buff4, ・・・・

としているのですが、
この1行分のテキストデータが一定でない(カンマの数が違う)場合が
あり、上手く読み込めません。

そこで、1行分のテキストデータを読み込み、読み込んだ後、カンマを
キーにして分解し、取得しようとしたのですが、


Line Input #1, buff

としたのですが、
データ中にみカンマが含まれている文字列が存在し、別物として分解
されてしまいます。

根本的にデータがおかしいとはわかるのですが、
異なる意味のデリミタに同じカンマが用いられていることがいけないですが、
上手く読み込む方法を教えて欲しいのですが。
または、データのフォーマットを修正するのが早いのでしょうか。

読み込むデータに、カンマが含まれているデータ(文字列)が存在した場合、
文字列の前後に、ダブルクォーテーション("")で囲んで区切りではなく、
文字とするとか。
このような方法で読み込んで、データを分解する方法を教えて下さい。

環境は、
Windows2000、VB6.0

投稿時間:2007/03/06(Tue) 17:27
投稿者名:花ちゃん
Eメール:
URL :
タイトル:
Re: カンマ区切りのCSVファイルの読み込み
過去のログ参照

http://hanatyan.sakura.ne.jp/logbbs/wforum.cgi?mode=allread&no=1572&page=0

投稿時間:2007/03/06(Tue) 23:27
投稿者名:べた
Eメール:
URL :
タイトル:
Re^2: カンマ区切りのCSVファイルの読み込み
> 過去のログ参照
>
> http://hanatyan.sakura.ne.jp/logbbs/wforum.cgi?mode=allread&no=1572&page=0

ありがとうございます。
参考になりました。

ただ、文字列中にカンマが含まれていて、文字列の前後がダブルクォーテーション("")で
囲まれていると上手くききません。


"ABC,DEF,GHI","JKL,MNO",………
のようなデータの場合、「ABC,DEF,GHI」をひとつのデータ、「JKL,MNO」,をひつつのデータ
と見てくれません。カンマで分解、取得さまれます。

もう一つも二つも工夫が必要なのでしょうか。
正しく取得するにはどうしたらよいのですか。

投稿時間:2007/03/07(Wed) 00:22
投稿者名:花ちゃん
Eメール:
URL :
タイトル:
Re^3: カンマ区切りのCSVファイルの読み込み
試して見ましたがちゃんと表示されましたよ。

http://bbs5.aimix-z.com/photovw.cgi?room=vbrescue&image=178.gif
このファイルを読み込んだら

このように表示さましたよ。
http://bbs5.aimix-z.com/photovw.cgi?room=vbrescue&image=177.gif

投稿時間:2007/03/07(Wed) 00:55
投稿者名:べた
Eメール:
URL :
タイトル:
Re^4: カンマ区切りのCSVファイルの読み込み
ありがとうございます。

ソースコードを記載します。
ファイルから読み込み、テキストボックスに表示しています。
確認しやすいように、文字列と文字列をコロンで区切っています。

Private Sub Command1_Click()
    Dim strTextLine As String
    Dim TmpTxt()    As String
    Dim dataN       As Integer
    Dim i           As Long
    Dim intFileNo   As Integer

    intFileNo = FreeFile
    Open "c:\tmp\sample2.txt" For Input As #intFileNo
    Do While Not EOF(intFileNo)
        Line Input #intFileNo, strTextLine
        TmpTxt = Split(strTextLine, ",")
        dataN = UBound(TmpTxt)
        For i = 0 To dataN
            If i = 0 Then
                Text1.Text = Text1.Text & Replace(TmpTxt(i), """", "")
            Else
                Text1.Text = Text1.Text & ":" & Replace(TmpTxt(i), """", "")
            End If
        Next i
        Text1.Text = Text1.Text & Chr(13) & Chr(10)
    Loop
    Close #intFileNo
End Sub

読み込んだデータ
"1ABC,DEF,GHI","JKL,MNO","123,456",3ABC,DEF,GHI"
"2ABC,DEF,GHI","JKL,MNO","3ABC,DEG,GHI"
"3ABC,DEG,GHI","3ABC,DEF,GHI"
"4ABC,DEG,GHI"

テキストボックスに表示した結果
1ABC:DEF:GHI:JKL:MNO:123:456:3ABC:DEF:GHI
2ABC:DEF:GHI:JKL:MNO:3ABC:DEG:GHI
3ABC:DEG:GHI:3ABC:DEF:GHI
4ABC:DEG:GHI

Splitの結果がどうしてもカンマで行われ、UBoundの結果がカンマの数に
なります。

投稿時間:2007/03/07(Wed) 08:07
投稿者名:ガッ
Eメール:
URL :
タイトル:
Re^5: カンマ区切りのCSVファイルの読み込み
過去ログのとろさんのソースを参考にすればいいのでは?

投稿時間:2007/03/07(Wed) 09:28
投稿者名:魔界の仮面弁士
Eメール:
URL :
タイトル:
Re^5: カンマ区切りのCSVファイルの読み込み
> この1行分のテキストデータが一定でない(カンマの数が違う)場合が
> あり、上手く読み込めません。
CSV としては奇妙ですね。
RFC4180 にある CSV 仕様 ≪http://www.ietf.org/rfc/rfc4180.txt≫ に従うならば、
行ごとに列数が異なる形式というのは推奨されていないようですし。(不可では無い)

》 Each line should contain the same number of fields throughout the file.
(各行が保持するフィールドの数は、ファイル全体を通じ、同一であるべきである。)


> 読み込んだデータ
> "1ABC,DEF,GHI","JKL,MNO","123,456",3ABC,DEF,GHI"
> "2ABC,DEF,GHI","JKL,MNO","3ABC,DEG,GHI"
> "3ABC,DEG,GHI","3ABC,DEF,GHI"
> "4ABC,DEG,GHI"

これは、データを見直すべきだと思いますよ。そもそも、当初の話では、
> データ中にみカンマが含まれている文字列が存在し、
ということでしたよね。
しかし提示されたデータ形式だと、データ中にカンマを含める事はできないように思えます。


なぜならば、「"」の数が奇数個であるからです。


RFC4180 による公式(≠標準)の CSV 仕様においては、データ両端を「"」で囲む場合に限り、
データ中に「改行(CrLf)」、「"」、「,」を含むことができるとされています。
しかしその場合、データ中の「"」は、判別のために「""」としてエスケープされなければ
ならない(must)とされていますので、『「"」が奇数個』という状況にはなりえないため、
これは『不正な CSV ファイル』として判断されることになります。

もし、この場合の「"」はフィールドを囲んでいるのではなく、データの一部であると
判断するのであれば、CSV ファイルとして利用可能ですが、その場合には、
「"1ABC」「DEF」「GHI"」「"JKL」「MNO"」「"123」「456"」「3ABC」「DEF」「GHI"」
「"2ABC」「DEF」「GHI"」「"JKL」「MNO"」「"3ABC」「DEG」「GHI"」
「"3ABC」「DEG」「GHI"」「"3ABC」「DEF」「GHI"」
「"4ABC」「DEG」「GHI"」
と判断されることになるため、データ中に「,」を含めることができなくなります。


もし、RFC4180 に記載の無い CSV 形式を採用しているのであれば、その仕様を
明確にしていただけないでしょうか。現在提示された情報だけでは、どこからどこまでが
一つのデータであるのか判断する事ができません。

投稿時間:2007/03/07(Wed) 10:13
投稿者名:ふく
Eメール:
URL :
タイトル:
Re^5: カンマ区切りのCSVファイルの読み込み
> "1ABC,DEF,GHI","JKL,MNO","123,456",3ABC,DEF,GHI"

> Splitの結果がどうしてもカンマで行われ、UBoundの結果がカンマの数に
> なります。

"1ABC,DEF,GHI","JKL,MNO","123,456",3ABC,DEF,GHI"の文字列を
カンマでSplitしたら当然そうなりますよね。
("1ABC)(DEF)(GHI")("JKL)(MNO")("123)(456")(3ABC)(DEF)(GHI")
カッコ内が配列内の文字列。

力技ですが、
(")でSplitして(,)のみのデータを飛ばして連結したらどうでしょうか?

*カッコ内は文字列をあらわします。

投稿時間:2007/03/07(Wed) 11:03
投稿者名:べた
Eメール:
URL :
タイトル:
Re^6: カンマ区切りのCSVファイルの読み込み
ガッさん、魔界の仮面弁士さん、ふくさん
ありがとうございます。

実際には、DAOを使わずに上手く行く方法はないのですね。
Splist関数内で正規表現とか使えませんし、
先頭から一文字ずつ見て判断していくしかないのでしょうか。

魔界の仮面弁士さんが指摘して頂いたこともありますが。

提示したデータが誤っていました。
"1ABC,DEF,GHI","JKL,MNO","123,456","3ABC,DEF,GHI"
"2ABC,DEF,GHI","JKL,MNO","3ABC,DEG,GHI"
"3ABC,DEG,GHI","3ABC,DEF,GHI"
"4ABC,DEG,GHI"

> "1ABC,DEF,GHI","JKL,MNO","123,456",3ABC,DEF,GHI"
は不正データして扱います。

投稿時間:2007/03/07(Wed) 11:08
投稿者名:YK
Eメール:
URL :
タイトル:
Re^7: カンマ区切りのCSVファイルの読み込み
>
> 実際には、DAOを使わずに上手く行く方法はないのですね。

こんにちは。

TEST版です。
Function StringSplit(mStr As String) As Variant
    Dim strArrys()  As String
    Dim strArry()   As String
    Dim strD        As String
    Dim varD()      As Variant
    Dim lngCnt      As Long
    Dim i           As Long
    Dim j           As Long

    strArrys = Split(mStr, ",")
    For i = 0 To UBound(strArrys)
        If strArrys(i) Like "*""" Then
            ReDim Preserve strArry(lngCnt)
            strArry(lngCnt) = strArrys(i)
            lngCnt = lngCnt + 1
        Else
            ReDim Preserve strArry(lngCnt)
            If strArrys(i) Like """*" Then
                For j = i To UBound(strArrys)
                    If strArrys(j) Like "*""" Then
                        strArry(lngCnt) = strArry(lngCnt) & strArrys(j)
                        Exit For
                    Else
                        strArry(lngCnt) = strArry(lngCnt) & strArrys(j) & ","
                        i = i + 1
                    End If
                Next
            Else
                strArry(lngCnt) = strArrys(i)
            End If
            lngCnt = lngCnt + 1
        End If

        strD = strArry(lngCnt - 1)
        ReDim Preserve varD(1 To lngCnt)
        ' "" で括られている場合削除
        If Left(strD, 1) = """" _
        And Right(strD, 1) = """" Then
            varD(lngCnt) = Mid(strD, 2, Len(strD) - 2)
        Else
            varD(lngCnt) = strD
        End If
    Next
    StringSplit = varD
End Function

Sub TEST()
    Dim intFno  As Integer
    Dim strFNm  As String
    Dim strD    As String
    Dim varD    As Variant
    Dim i       As Long

    strFNm = "D:\Comma.csv"
    intFno = FreeFile
    Open strFNm For Input As intFno

    Do While Not EOF(intFno)
        Line Input #intFno, strD
        varD = StringSplit(strD)
        For i = 1 To UBound(varD)
            Debug.Print varD(i),
        Next
        Debug.Print
    Loop
    Close #intFno
End Sub

投稿時間:2007/03/07(Wed) 12:13
投稿者名:魔界の仮面弁士
Eメール:
URL :
タイトル:
Re^7: カンマ区切りのCSVファイルの読み込み
> 提示したデータが誤っていました。
(中略)
> "3ABC,DEG,GHI","3ABC,DEF,GHI"
> "4ABC,DEG,GHI"

列数可変のCSVの場合、最終行の扱いも重要です。

A.CSV …… "3ABC,DEG,GHI","3ABC,DEF,GHI"(改行)"4ABC,DEG,GHI"(ファイル終端)
B.CSV …… "3ABC,DEG,GHI","3ABC,DEF,GHI"(改行)"4ABC,DEG,GHI"(改行)(ファイル終端)

という 2種のファイルがあった場合、
A.CSV は 2行構成(1行目=2列、2行目=1列)である事が明らかですが、
B.CSV は 3行構成(1行目=2列、2行目=1列、3行目=0列)か 2行構成かが曖昧になりますので。

> Splist関数内で正規表現とか使えませんし、
データ中に含まれる特殊記号が「,」だけで、「"」や改行がありえないなら、

 Line Input #fno, rawLineText
 Cols = Split(rawLineText, """,""")
 If LBound(Cols) <= UBound(Cols) Then
  Cols(LBound(Cols)) = Mid(Cols(LBound(Cols)), 2)
  Cols(UBound(Cols)) = Left(UBound(Cols), Len(UBound(Cols)) - 1)
 End If

のような処理でいけるかも知れません。試していませんけど。

投稿時間:2007/03/07(Wed) 12:58
投稿者名:べた
Eメール:
URL :
タイトル:
Re^8: カンマ区切りのCSVファイルの読み込み
YKさん、魔界の仮面弁士さん
ありがとうございます。

YKさん
記載して頂いたソースコード試して見ました。
問題なく動きました。
期待した結果が得られている見たいです。

魔界の仮面弁士さん
記載して頂いたソースコードですが、

> Cols(UBound(Cols)) = Left(UBound(Cols), Len(UBound(Cols)) - 1)

で、エラーとなります。
「コンパイルエラー 変数が必要です。」
のVBのエラーがでます。

投稿時間:2007/03/07(Wed) 13:08
投稿者名:魔界の仮面弁士
Eメール:
URL :
タイトル:
Re^9: カンマ区切りのCSVファイルの読み込み
> 「コンパイルエラー 変数が必要です。」

おっと失礼。こうかな。

Dim Cols() As String
Dim rawLineText As String

  rawLineText = """2ABC,DEF,GHI"",""JKL,MNO"",""3ABC,DEG,GHI"""
  Cols = Split(rawLineText, """,""")
  If LBound(Cols) <= UBound(Cols) Then
    Cols(LBound(Cols)) = Mid(Cols(LBound(Cols)), 2)
    If Right(Cols(UBound(Cols)), 1) = """" Then
        Cols(UBound(Cols)) = Left(Cols(UBound(Cols)), Len(Cols(UBound(Cols))) - 1)
    End If
  End If

投稿時間:2007/03/07(Wed) 14:11
投稿者名:べた
Eメール:
URL :
タイトル:
Re^10: カンマ区切りのCSVファイルの読み込み
魔界の仮面弁士さん
動きました。