

'***************************************************************************************************
'   CSV形式ファイル読み込み処理(カンマ数不定処理)                   Module1(Module)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
' [参照設定]
'   ・Microsoft Scripting Runtime
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'03/07/25(1.00)新規作成
'20/03/17(1.10)*.xlsm化、他
'***************************************************************************************************
Option Explicit
Option Private Module
'===================================================================================================
Private Const g_cnsTitle As String = "テキストファイル読み込み処理"
Private Const g_cnsFilter As String = "全てのファイル (*.*),*.*"
Private Const g_cnsStartRow As Long = 2                         ' 読み込み開始行
Private Const g_cnsStartCol As Long = 1                         ' 読み込み開始カラム
'***************************************************************************************************
'   ■■■ ワークシート側からの呼び出し処理 ■■■
'***************************************************************************************************
'* 処理名 :READ_TextFile
'* 機能  :CSV形式テキストファイル(不定カラム)読み込みサンプル
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :(なし)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2003年07月25日
'* 作成者 :井上 治
'* 更新日 :2020年03月17日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:項目内改行の対応無しの前提となります
'***************************************************************************************************
Sub READ_TextFile()
    '-----------------------------------------------------------------------------------------------
    Dim objFso As FileSystemObject                                  ' FileSystemObject
    Dim objTs As TextStream                                         ' TextStream
    Dim lngRow As Long                                              ' セルの行番号
    Dim lngRec As Long                                              ' レコード件数カウンタ
    Dim lngCol As Long                                              ' CSV項目カラムINDEX
    Dim strFilename As String                                       ' ファイル名(フルパス)
    Dim vntFilename As Variant                                      ' ファイル名(受け取り)
    Dim vntRec As Variant                                           ' レコード内容(配列)
    '-----------------------------------------------------------------------------------------------
    ' 「ファイルを開く」ダイアログでファイル名の指定を受ける
    Application.StatusBar = "読み込むファイル名を指定して下さい。"
    vntFilename = Application.GetOpenFilename(FileFilter:=g_cnsFilter, Title:=g_cnsTitle)
    ' キャンセルされた場合は以降の処理は行なわない
    If VarType(vntFilename) = vbBoolean Then Exit Sub
    strFilename = vntFilename
    '-----------------------------------------------------------------------------------------------
    ' 指定ファイルをOPEN(入力モード)
    Set objFso = New FileSystemObject
    Set objTs = objFso.OpenTextFile(strFilename, ForReading)
    lngRow = g_cnsStartRow - 1
    ' EOF(End of File)まで繰り返す
    Do Until objTs.AtEndOfStream
        ' レコード件数カウンタの加算
        lngRec = lngRec + 1
        Application.StatusBar = "読み込み中です....(" & lngRec & "レコード目)"
        ' 行単位にレコードを読み込む(共通処理)
        vntRec = modGetCSVRec3.FP_GET_CSV_REC2(objTs)
        lngCol = UBound(vntRec) + g_cnsStartCol
        ' 行を加算しレコード内容を配列転記(先頭は2行目)
        lngRow = lngRow + 1
        Range(Cells(lngRow, g_cnsStartCol), Cells(lngRow, lngCol)).Value = vntRec
    Loop
    '-----------------------------------------------------------------------------------------------
    ' 指定ファイルをCLOSE
    objTs.Close
    Application.StatusBar = False
    ' 処理終了
    Set objTs = Nothing
    Set objFso = Nothing
    ' 終了の表示
    MsgBox "ファイル読み込みが完了しました。" & vbCr & _
        "レコード件数=" & lngRec & "件", vbInformation, g_cnsTitle
End Sub
'----------------------------------------<< End of Source >>----------------------------------------
'***************************************************************************************************
'   CSV形式ファイル読み込み処理(カンマ数不定処理)                   modGetCSVRec3(Module)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
' [参照設定]
'   ・Microsoft Scripting Runtime
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'03/07/25(1.00)新規作成
'20/03/17(1.10)*.xlsm化、他
'***************************************************************************************************
Option Explicit
Option Private Module
'===================================================================================================
Private Const g_cnsDq As String = """"
Private Const g_cnsDqCom As String = ""","
Private Const g_cnsCom As String = ","
Private Const g_cnsBlnk As String = ""
Private Const g_cnsProd As String = "."
'***************************************************************************************************
'   ■■■ 共通サブ処理 ■■■
'***************************************************************************************************
'* 処理名 :FP_GetCsvRec3
'* 機能  :CSV形式の1レコードの受け取り
'---------------------------------------------------------------------------------------------------
'* 返り値 :CSVレコード内容の1次配列(Array:Variant)
'* 引数  :Arg1 = TextStream(Object)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2003年07月25日
'* 作成者 :井上 治
'* 更新日 :2020年03月17日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:※現時点ではエラー処理なし
'***************************************************************************************************
Public Function FP_GetCsvRec3(objTs As TextStream) As Variant
    '-----------------------------------------------------------------------------------------------
    Dim lngPos As Long                                              ' 項目先頭カラム
    Dim lngPos2 As Long                                             ' 項目間のカンマ位置
    Dim lngIx As Long                                               ' 項目テーブルINDEX
    Dim lngLen As Long                                              ' レコード長
    Dim lngErr As Long                                              ' エラーコード
    Dim swTrue As Boolean                                           ' レコード連結判断スイッチ
    Dim swDq As Boolean                                             ' ダブルクォーテーションスイッチ
    Dim dteDate As Date                                             ' 日付試験用Work
    Dim strRec As String                                            ' レコード内容(連結後)
    Dim strRec2 As String                                           ' レコード内容(連結前)
    Dim strText As String                                           ' 1項目の内容
    Dim strText2 As String                                          ' Work
    Dim strChar As String                                           ' 1文字Work
    Dim tblFld() As Variant                                         ' レコード内容テーブル
    strRec = ""
    ' 項目途中改行対応のため、行末判定は独自に行なう
    Do Until swTrue
        '-----------------------------------------------------------------------
        swTrue = True
        ' レコードの読込み(TextStream)
        strRec2 = objTs.ReadLine
        ' 分断レコード対応のため文字列を接合する
        strRec = strRec & strRec2
        lngLen = Len(strRec)
        ' 配列を初期化
        lngIx = -1
        ReDim tblFld(0)
        ' レコード内容を1文字ずつ判定する
        lngPos = 1
        '-----------------------------------------------------------------------
        ' レコードの終端までのループ
        Do While lngPos <= lngLen
            '===================================================================
            ' 項目の次のカンマ位置探索用
            lngPos2 = lngPos + 1
            swDq = False
            strChar = Mid(strRec, lngPos, 1)
            ' 現在文字を判定
            Select Case strChar
                Case g_cnsDq
                    '=================================================
                    ' ダブルクォーテーション
                    '-------------------------------------------------
                    swDq = True
                    ' 先頭がダブルクォーテーションの場合、項目末の同文字を探す
                    Do While lngPos2 < lngLen
                        ' ダブルクォーテーション+カンマ判定か
                        If Mid(strRec, lngPos2, 2) = g_cnsDqCom Then Exit Do
                        ' 次の文字へ
                        lngPos2 = lngPos2 + 1
                    Loop
                    ' 行末か
                    If lngPos2 >= lngLen Then
                        ' 行末に達した場合は正しい文字列か判定する
                        If Right(strRec, 1) = g_cnsDq Then
                            strText = Trim(Mid(strRec, lngPos + 1, lngLen - lngPos - 1))
                        Else
                            ' 不揃いの場合は次レコードを読み込むように指示する
                            strText = g_cnsBlnk
                            swTrue = False
                        End If
                    ElseIf lngPos2 > (lngPos + 1) Then
                        ' 両端のダブルクォーテーションを外す
                        strText = Trim(Mid(strRec, lngPos + 1, lngPos2 - lngPos - 1))
                    Else
                        strText = g_cnsBlnk
                    End If
                    ' 次の文字へ
                    lngPos2 = lngPos2 + 1
                Case g_cnsCom
                    '=================================================
                    ' カンマ
                    '-------------------------------------------------
                    ' カンマのみの場合はEmptyをセットさせる
                    strText = ""
                    ' 次の文字へ
                    lngPos2 = lngPos2 + 1
                Case Else
                    '=================================================
                    ' その他
                    '-------------------------------------------------
                    ' 先頭がダブルクォーテーションでない場合は単純にカンマを探す
                    Do While lngPos2 <= lngLen
                        ' カンマ発見か
                        If Mid(strRec, lngPos2, 1) = g_cnsCom Then Exit Do
                        ' 次の文字へ
                        lngPos2 = lngPos2 + 1
                    Loop
                    If lngPos2 > lngPos Then
                        strText = Trim(Mid(strRec, lngPos, lngPos2 - lngPos))
                    Else
                        strText = g_cnsBlnk
                    End If
            End Select
            '===================================================================
            ' テーブル要素数を追加して内容をセット
            lngIx = lngIx + 1
            ReDim Preserve tblFld(lngIx)
            ' 一旦大文字変換
            strText2 = UCase(strText)
            ' 状態判定
            Select Case True
                Case (IsNumeric(strText) And Not swDq)
                    '=================================================
                    ' 数値でダブルクォーテーションで囲われていない
                    '-------------------------------------------------
                    ' 小数点があるか
                    If InStr(1, strText, g_cnsProd, vbTextCompare) <> 0 Then
                        tblFld(lngIx) = CDbl(strText)   ' 実数は浮動小数点型に設定
                    Else
                        tblFld(lngIx) = CCur(strText)   ' 整数は通貨型に設定
                    End If
                Case IsDate(strText)
                    '=================================================
                    ' 日付
                    '-------------------------------------------------
                    tblFld(lngIx) = CDate(strText)      ' 日付型
                    On Error Resume Next
                    dteDate = tblFld(lngIx)
                    lngErr = Err.Number
                    On Error GoTo 0
                    If lngErr <> 0 Then
                        ' 日付エラー!
                        tblFld(lngIx) = strText         ' 文字列型に変更
                    ElseIf dteDate < #1/1/1900#Then
                        ' 日付範囲外
                        tblFld(lngIx) = strText         ' 文字列型に変更
                    Else
                        tblFld(lngIx) = dteDate
                    End If
                Case ((strText2 = "TRUE") Or (strText2 = "FALSE"))
                    '=================================================
                    ' BOOL
                    '-------------------------------------------------
                    tblFld(lngIx) = CBool(strText)      ' Boolean型
                Case strText <> g_cnsBlnk
                    '=================================================
                    ' 有効文字列
                    '-------------------------------------------------
                    tblFld(lngIx) = strText             ' 文字列型
                Case Else
                    '=================================================
                    ' 空項目
                    '-------------------------------------------------
                    ' ブランクの場合は初期化(Empty)
                    tblFld(lngIx) = Empty
            End Select
            ' 次項目の先頭位置をセット
            lngPos = lngPos2 + 1
        Loop
        '-----------------------------------------------------------------------
        ' EOFの場合は無条件に終了とする
        If objTs.AtEndOfStream Then swTrue = True
    Loop
    ' 配列を戻り値にセット
    FP_GetCsvRec3 = tblFld
End Function
'----------------------------------------<< End of Source >>----------------------------------------

| ファイル名 | 内容等 | 
|---|---|
| ReadCsvFile4SJIS.xlsm | CSV形式ファイル読み出し機能サンプル(シフトJIS版) ※マクロ有効ブック サンプルの起動プロシージャは「TEST1」です。(起動ボタン等はありません) | 
| ReadCsvFile4UTF8.xlsm | CSV形式ファイル読み出し機能サンプル(UTF-8版)   ※マクロ有効ブック サンプルの起動プロシージャは「TEST2」です。(起動ボタン等はありません) | 
| テストデータ.csv | 下の画像の簡単なCSV形式ファイルサンプルデータ(シフトJIS版のみ) | 



| 定数名 | 意味 | 
|---|---|
| g_cnsCheckColCnt | カラム数によるチェックを行なうかどうかの判定です。Trueにすると不正カラム数のレコードがあるとエラーになります。 Falseにした場合はチェックは行ないません。 | 
| g_cnsColCnt | チェックを行なう場合のカラム数です。 このサンプルの場合はこの定数をシートに貼り付ける列数として利用しています。実際のCSV形式ファイルの列数より大きい値になっていると実行時エラーになります。 | 
'***************************************************************************************************
'   CSV読み込みテスト                                                   Module1(Module)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'19/11/06(1.00)新規作成
'19/11/09(1.10)カラム数チェック有無の指定を追加
'***************************************************************************************************
Option Explicit
'===================================================================================================
Private Const g_cnsTitle As String = "CSV読み込みテスト"
Private Const g_cnsCheckColCnt As Boolean = True                    ' カラム数チェック有無
Private Const g_cnsColCnt As Long = 10                              ' カラム数
' ↑CSVファイルのカラム数をg_cnsColCntにセットしてから実行して下さい
'   チェック不要の場合はg_cnsCheckColCntをFalseに変更して下さい
'***************************************************************************************************
'* 処理名 :TEST1
'* 機能  :CSV読み込みテスト
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :(なし)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2019年11月06日
'* 作成者 :井上 治
'* 更新日 :2019年11月09日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:
'***************************************************************************************************
Public Sub TEST1()
    '-----------------------------------------------------------------------------------------------
    Dim lngIxR As Long                                              ' テーブルINDEX(Row)
    Dim lngIxC As Long                                              ' テーブルINDEX(Col)
    Dim lngIxRMax As Long                                           ' テーブルINDEX上限(Row)
    Dim strFilename As String                                       ' ファイル名
    Dim strErrMSG As String                                         ' エラーメッセージ
    Dim vntFilename As Variant                                      ' ファイル名(受け取り)
    Dim tblRec As Variant                                           ' JAG配列テーブル
    Dim tblRec2() As Variant                                        ' 二次元配列テーブル
    '-----------------------------------------------------------------------------------------------
    ' ファイル名受け取り
    vntFilename = Application.GetOpenFilename("CSVファイル (*.csv;*.txt),*.csv;*.txt", , g_cnsTitle)
    ' キャンセルは終了
    If VarType(vntFilename) = vbBoolean Then Exit Sub
    strFilename = vntFilename
    '-----------------------------------------------------------------------------------------------
    ' CSV読み込みクラス(Ascii/シフトJIS)
    With New clsReadCsv1
        ' カラム数チェック有無を指定
        .prpCheckColCnt = g_cnsCheckColCnt
        ' カラム数を指定
        .prpColCnt = g_cnsColCnt
        ' CSV読み込み
        If Not .ReadCsv(strFilename, tblRec) Then
            MsgBox .prpErrMSG, vbCritical, g_cnsTitle
            Exit Sub
        End If
    End With
    '===============================================================================================
    ' 以下はサンプルとしての結果検証用の記述です
    ' カラム数チェックを行なわない指定でもg_cnsColCntの指定列までしかシートには書き出されません
    '-----------------------------------------------------------------------------------------------
    lngIxRMax = UBound(tblRec)
    ReDim tblRec2(lngIxRMax, g_cnsColCnt - 1)
    ' JAG配列テーブルを二次元配列テーブルに変換
    Do While lngIxR <= lngIxRMax
        lngIxC = 0
        ' カラム方向ループ
        Do While lngIxC < g_cnsColCnt
            tblRec2(lngIxR, lngIxC) = tblRec(lngIxR)(lngIxC)
            ' 次へ
            lngIxC = lngIxC + 1
        Loop
        ' 次へ
        lngIxR = lngIxR + 1
    Loop
    ReDim tblRec(0)
    '-----------------------------------------------------------------------------------------------
    ' 現在シートに貼り付け
    With ActiveSheet
        .Range(.Cells(1, 1), .Cells(lngIxR, g_cnsColCnt)).Value = tblRec2
    End With
End Sub
'----------------------------------------<< End of Source >>----------------------------------------
'***************************************************************************************************
'   CSV読み込みクラス                                               clsReadCsv1(Class)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
'   [前提条件]
'   ・カンマ区切りテキストファイルであること
'   ・文字コードはAscii/シフトJIS形式
'   ・改行コードはCR、LF、CRLFに対応
'   ・フィールド数は全行一致していること(チェック有効時)
'   ・フィールド内で改行、あるいはフィールド内にカンマ、ダブルクォーテーションがある場合は
'    フィールド自体をダブルクォーテーションで囲うこと
'***************************************************************************************************
'   [参照設定]
'   ・Microsoft Scripting Runtime
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'19/11/06(1.00)新規作成
'19/11/09(1.10)LFコードのみの改行に対応、カラム数チェック有無の指定を追加
'***************************************************************************************************
Option Explicit
'===================================================================================================
Private Const g_cnsCom As String = ","
Private Const g_cnsDq As String = """"
'---------------------------------------------------------------------------------------------------
Private g_blnCheckColCnt As Boolean                                 ' カラム数チェック有無
Private g_lngColCnt As Long                                         ' チェック時のカラム数
Private g_strErrMSG As String                                       ' エラーメッセージ
'***************************************************************************************************
'   ■■■ 公開プロシージャ ■■■
'***************************************************************************************************
'* 処理名 :ReadCsv
'* 機能  :CSV読み込み
'---------------------------------------------------------------------------------------------------
'* 返り値 :処理成否(Boolean)
'* 引数  :Arg1 = ファイル名(String)                      ※フルパス
'*      Arg2 = CSV内容JAG配列テーブル(Variant)         ※Ref参照
'---------------------------------------------------------------------------------------------------
'* 作成日 :2019年11月06日
'* 作成者 :井上 治
'* 更新日 :2019年11月09日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:
'***************************************************************************************************
Friend Function ReadCsv(ByVal strFilename As String, _
                        ByRef tblRec As Variant) As Boolean
    '-----------------------------------------------------------------------------------------------
    Dim strAllRec As String                                         ' レコード全体
    ReadCsv = False
    g_strErrMSG = ""
    ReDim tblRec(0)
    ' カラム数未設定は終了(チェック有効時)
    If g_blnCheckColCnt And g_lngColCnt = 0 Then
        g_strErrMSG = "カラム数が設定されていません。"
        Exit Function
    End If
    ' CSVファイル読み込み
    If Not FP_ReadFile(strFilename, strAllRec) Then Exit Function
    ' CSVファイル内容をJAG配列に変換
    If Not FP_GetJagTable(strAllRec, tblRec) Then Exit Function
    ' 終了
    ReadCsv = True
End Function
'***************************************************************************************************
'   ■■■ サブ処理 ■■■
'***************************************************************************************************
'* 処理名 :FP_ReadFile
'* 機能  :CSVファイル読み込み
'---------------------------------------------------------------------------------------------------
'* 返り値 :処理成否(Boolean)
'* 引数  :Arg1 = ファイル名(String)                      ※フルパス
'*      Arg2 = レコード全体(String)                    ※Ref参照
'---------------------------------------------------------------------------------------------------
'* 作成日 :2019年11月06日
'* 作成者 :井上 治
'* 更新日 :2019年11月06日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:
'***************************************************************************************************
Private Function FP_ReadFile(ByVal strFilename As String, _
                             ByRef strAllRec As String) As Boolean
    '-----------------------------------------------------------------------------------------------
    Dim objFso As FileSystemObject                                  ' FileSystemObject
    Dim objTs As TextStream                                         ' TextStream
    Dim blnOpen As Boolean                                          ' OPEN判定
    FP_ReadFile = False
    On Error GoTo ReadFile_ERROR
    Set objFso = New FileSystemObject
    ' CSVファイルOPEN
    Set objTs = objFso.OpenTextFile(strFilename, ForReading, False)
    blnOpen = True
    ' ファイル全量を読み込み
    strAllRec = objTs.ReadAll
    FP_ReadFile = True
    GoTo ReadFile_EXIT
'===================================================================================================
ReadFile_ERROR:
    g_strErrMSG = Err.Description
'===================================================================================================
ReadFile_EXIT:
    ' CSVファイルCLOSE
    If blnOpen Then objTs.Close
    Set objTs = Nothing
    Set objFso = Nothing
    On Error GoTo 0
End Function
'***************************************************************************************************
'* 処理名 :FP_GetJagTable
'* 機能  :CSVファイル内容をJAG配列に変換
'---------------------------------------------------------------------------------------------------
'* 返り値 :処理成否(Boolean)
'* 引数  :Arg1 = レコード全体(String)
'*      Arg2 = CSV内容JAG配列テーブル(Variant)         ※Ref参照
'---------------------------------------------------------------------------------------------------
'* 作成日 :2019年11月06日
'* 作成者 :井上 治
'* 更新日 :2019年11月09日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:
'***************************************************************************************************
Private Function FP_GetJagTable(ByRef strAllRec As String, _
                                ByRef tblRec As Variant) As Boolean
    '-----------------------------------------------------------------------------------------------
    ' 全体で使用する変数
    Dim lngIxRec As Long                                            ' レコードINDEX
    Dim lngPos As Long                                              ' 現在文字位置
    Dim lngPosEnd As Long                                           ' 最終文字位置
    Dim lngCntRec As Long                                           ' レコードカウンタ
    ' レコード単位で使用する変数
    Dim lngIxFld As Long                                            ' フィールドINDEX
    Dim lngCntFld As Long                                           ' フィールドカウンタ
    Dim blnCrLf As Boolean                                          ' 改行判定
    Dim blnOkRec As Boolean                                         ' 有効レコード判定
    Dim tblFld() As String                                          ' フィールドテーブル
    ' フィールド単位で使用する変数
    Dim lngPosS As Long                                             ' 項目開始位置
    Dim lngPosE As Long                                             ' 項目終了位置
    Dim lngPosS2 As Long                                            ' 項目開始位置(DQ調整後)
    Dim lngPosE2 As Long                                            ' 項目終了位置(DQ調整後)
    Dim blnInText As Boolean                                        ' 文字列項目内判定
    Dim blnDq As Boolean                                            ' ダブルクォーテーション判定
    Dim blnDq2 As Boolean                                           ' 文字列内DQ発生判定
    Dim strText As String                                           ' 項目テキストWORK
    '-----------------------------------------------------------------------------------------------
    FP_GetJagTable = False
    lngPos = 1
    lngIxRec = -1
    lngPosEnd = Len(strAllRec)
    ' 内容無しはエラー
    If lngPosEnd = 0 Then
        g_strErrMSG = "ファイルに内容が書き込まれていません。"
        Exit Function
    End If
    '-----------------------------------------------------------------------------------------------
    ' 最終文字位置まで繰り返す
    Do While lngPos <= lngPosEnd
        '=============================================================
        ' レコード単位[前]処理
        '-------------------------------------------------------------
        blnCrLf = False
        blnOkRec = False
        lngIxFld = -1
        lngCntFld = 0
        ReDim tblFld(0)
        '=============================================================
        ' レコード単位[主]処理(レコード内項目巡回)
        '-------------------------------------------------------------
        Do While lngPos <= lngPosEnd
            '-----------------------------------------------
            ' フィールド単位[前]処理
            '-----------------------------------------------
            blnInText = False
            blnDq = False
            blnDq2 = False
            ' 項目先頭位置
            lngPosS = lngPos
            '-----------------------------------------------
            ' フィールド単位[主]処理
            '-----------------------------------------------
            Do While lngPos <= lngPosEnd
                ' 現在文字を判定
                Select Case Mid(strAllRec, lngPos, 1)
                    Case vbCr                               ' CRコード
                        ' 文字列項目内でなければレコード終了
                        If Not blnInText Then
                            blnCrLf = True
                            Exit Do
                        End If
                    Case vbLf                               ' LFコード
                        ' 文字列項目内でなければレコード終了
                        If Not blnInText Then
                            blnCrLf = True
                            Exit Do
                        End If
                    Case g_cnsDq                            ' ダブルクォーテーション
                        ' 文字列内DQ発生判定か
                        If blnInText Then
                            blnDq2 = True
                        End If
                        blnInText = Not blnInText
                        blnDq = True
                    Case g_cnsCom                           ' カンマ
                        ' 文字列項目内でなければ項目終了
                        If Not blnInText Then Exit Do
                End Select
                ' 次の文字へ
                lngPos = lngPos + 1
            Loop
            '-----------------------------------------------
            ' フィールド単位[後]処理
            '-----------------------------------------------
            ' 項目終了位置(実際は次のカンマ位置)
            lngPosE = lngPos
            lngPosS2 = lngPosS
            lngPosE2 = lngPosE
            ' ダブルクォーテーションで囲われているか
            If blnDq Then
                ' 両端文字(ダブルクォーテーション)を除外
                lngPosS2 = lngPosS + 1
                lngPosE2 = lngPosE - 1
            End If
            lngCntFld = lngCntFld + 1
            ' フィールドテーブル要素を追加
            lngIxFld = lngIxFld + 1
            ReDim Preserve tblFld(lngIxFld)
            ' 有効なフィールドか(ブランクでないか)
            If lngPosE2 > lngPosS2 Then
                blnOkRec = True
                ' 項目テキストの取り出し
                strText = Mid(strAllRec, lngPosS2, lngPosE2 - lngPosS2)
                ' 文字列内ダブルクォーテーション発生判定
                If blnDq2 Then
                    ' ダブルクォーテーション連記を解除(完璧な方法ではない)
                    strText = Replace(strText, """""", """")
                End If
                ' フィールドテーブルに格納
                tblFld(lngIxFld) = strText
            End If
            ' カンマ、改行を除外するため+1
            lngPos = lngPosE + 1
            ' レコード終了判定
            If blnCrLf Then Exit Do
        Loop
        '=============================================================
        ' レコード単位[後]処理
        '-------------------------------------------------------------
        ' Cr後のLfは除外
        If Mid(strAllRec, lngPos, 1) = vbLf Then
            lngPos = lngPos + 1
        End If
        ' 有効レコードならJAG配列テーブルに格納
        If blnOkRec Then
            lngCntRec = lngCntRec + 1
            ' 項目数判定
            If g_blnCheckColCnt And lngCntFld <> g_lngColCnt Then
                Call GP_AppendMessage(CStr(lngCntRec) & "REC目、項目数不正(" & lngCntFld & ")")
            End If
            lngIxRec = lngIxRec + 1
            ReDim Preserve tblRec(lngIxRec)
            tblRec(lngIxRec) = tblFld
        End If
    Loop
    ' 有効内容無し
    If lngCntRec = 0 Then
        g_strErrMSG = "有効な内容がありません。"
    End If
    ' エラーがなければOK
    FP_GetJagTable = g_strErrMSG = ""
End Function
'***************************************************************************************************
'* 処理名 :GP_AppendMessage
'* 機能  :メッセージ累積
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :Arg1 = 今回メッセージ(String)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2019年11月06日
'* 作成者 :井上 治
'* 更新日 :2019年11月06日
'* 更新者 :井上 治
'* 機能説明:改行を挟んでメッセージを累積する
'* 注意事項:
'***************************************************************************************************
Private Sub GP_AppendMessage(ByVal strAddMSG As String)
    '-----------------------------------------------------------------------------------------------
    If g_strErrMSG <> "" Then g_strErrMSG = g_strErrMSG & vbCrLf
    g_strErrMSG = g_strErrMSG & strAddMSG
End Sub
'***************************************************************************************************
'   ■■■ プロパティ ■■■
'***************************************************************************************************
'   カラム数チェック有無(Boolean)
'---------------------------------------------------------------------------------------------------
Friend Property Let prpCheckColCnt(ByVal blnValue As Boolean)
    g_blnCheckColCnt = blnValue
End Property
'===================================================================================================
'   チェック時のカラム数(Long)
'---------------------------------------------------------------------------------------------------
Friend Property Let prpColCnt(ByVal lngValue As Long)
    g_lngColCnt = lngValue
End Property
'===================================================================================================
'   エラーメッセージ(String)
'---------------------------------------------------------------------------------------------------
Friend Property Get prpErrMSG() As String
    prpErrMSG = g_strErrMSG
End Property
'----------------------------------------<< End of Source >>----------------------------------------
| プロシージャ | 処理内容 | 
|---|---|
| FP_ReadFile | 指定ファイル名のCSV形式ファイルをEOFまで全量を読み出し、文字列変数で返す処理です。 この処理は「clsReadCsv1」と「clsReadCsv2」で文字コードの違いから処理記述が異なります。 | 
| FP_GetJagTable | 渡されたファイル全量の内容から1文字ずつ判定しながら列方向の配列を作成し、さらに行方向の配列に列方向の配列を納めていく作業を行なう処理で、
            結果としてJAG配列を返します。 この処理は「clsReadCsv1」「clsReadCsv2」とも処理記述は全く同じです。 全体ループ(EOFまで)、レコード単位ループ(セル外の改行発見まで)、 フィールドループ(項目境界かセル外改行が見つかるまで)の3重ループ処理になっています。 | 
|  | ←ReadCsvFile4.zip (56KB) |