Обработка VBScript CSV (RFC4180)

Позвольте мне предвосхитить это, сказав, что я сисадмин с небольшим воздействием на разработчика. Если это не вопрос для stackru, пожалуйста, не стесняйтесь перемещать / удалять / указывать меня в правильном направлении.

Я пытаюсь прочитать csv-файл, совместимый с RFC4180, и выбросить каждое значение в массив для дальнейшей обработки по сценарию. Ниже приведена наиболее замысловатая, но совместимая линия CSV, которую я смог придумать, и она работает, но этот сценарий будет ориентирован на клиентов, поэтому я хотел бы, чтобы вы посмотрели и протестировали логику / показали, где Я пропустил вещи.

Я бы тоже хотел указатели лучших практик, если это возможно.

Это выдержка, в основном я читаю в строке из файла CSV и перебираю каждый символ, тестирую и применяю разные вещи, основываясь на моем понимании RFC 4180. chr(34) представляет двойные кавычки ("), это единственный способ Я мог бы найти, чтобы сделать сравнение в VBScript.

If isFirstChar = True And thisChar = chr(34) Then
    'Mark it as in quotes, but don't print it, as it's not part of the text meant for the din file
    isInQuotes = True
    isFirstChar = False
ElseIf thisChar = chr(34) And isInQuotes = True Then
    If nextChar = chr(34) Then
    'Per RFC4108, "" is an escape sequence
    'Print it, jump up the old CharCounter to prevent double handling.
        CharCounter = CharCounter +1
        FieldData = FieldData & thisChar
        isFirstChar = False
    ElseIf nextChar = "," Then
    'It's the end of the field, we can set the isInQuotes to false so that the next char is handled as end of field
    isInQuotes = False
    isFirstChar = False
    Else
    'CSV isn't RFC4180 compliant
    WScript.Echo "This CSV isn't RFC4180 compliant, please fix the file or contact <redacted> for assistance."
    End If
ElseIf thisChar = "," Then
    If isInQuotes = False Then
    'End of Field, handle appropriately
        FieldCounter = FieldCounter + 1
        Redim Preserve FieldArray(FieldCounter)
        FieldArray(FieldCounter) = FieldData
        FieldData = ""
        isFirstChar = True
    Else
    'In quotes, handle as regular char
    FieldData = FieldData & thisChar
    isFirstChar = False
    End If
Else
    'Got all the way here, it's just a regular character! (We hope)
    FieldData = FieldData & thisChar
    isFirstChar = False
End If

А ниже приведен пример строки из записи CSV:

"Luke ,, Pearson","Luke ""Lucky""","""111 ""Brown Mountain Cres",,"CO""OROY",QLD,4563,,1234567,1,1.11,N,AT FRONT GATE,0712345678,0.0022,2

1 ответ

Я хотел автономное решение, поэтому вот что я придумал. (Я уверен, что есть возможности для улучшения):

       Private Function CSVSplit(ByVal csv As String) As String()
    ' see RFC 4180
    If csv = Empty Then
        Dim emptyArray(-1 To -1) As String
        CSVSplit = emptyArray
        Exit Function
    End If

    Dim i As Long
    Dim tokenBuf As Collection: Set tokenBuf = New Collection
    Dim tokens As Collection: Set tokens = New Collection
    Dim token As String
    Dim inQuotes As Boolean
    Dim nextChar As String
    Dim c_ As Variant

    For i = 1 To Len(csv)
        Dim c As String: c = Mid(csv, i, 1)

        If i = Len(csv) Then
            nextChar = Empty
        Else
            nextChar = Mid(csv, i + 1, 1)
        End If

        Select Case c
            Case ","
                If inQuotes Then
                    Call tokenBuf.Add(c)
                Else
                    token = ""
                    For Each c_ In tokenBuf
                        token = token & c_
                    Next
                    Call tokens.Add(token)
                    Set tokenBuf = New Collection
                End If

            Case """"
                If Not inQuotes Then
                    inQuotes = True
                ElseIf nextChar = """" Then
                    i = i + 1
                    c = Mid(csv, i, 1)
                    ' quote literal
                    Call tokenBuf.Add(c)
                Else
                    inQuotes = False
                End If

            Case Else
                Call tokenBuf.Add(c)
        End Select
    Next

    token = ""
    For Each c_ In tokenBuf
        token = token & c_
    Next
    Call tokens.Add(token)

    Dim result() As String
    ReDim result(tokens.count - 1)

    For i = 0 To tokens.count - 1
        result(i) = tokens(i+1)
    Next

    CSVSplit = result
End Function

Протестировано со следующим (обратите внимание наWriteLinefunction - это просто пользовательская функция, которая выводит на консоль для целей тестирования.:

      Dim s As Variant
Dim ss(3) As String
ss(0) = "Panes, Trains, Automobiles"

ss(1) = "Wide, He Said ""Tall, Skinny and round"", ""Narrow, but """"manageable"""""

ss(2) = "Speaker: Cindy, Greeting: """"""Hello, " & vbNewLine & "world"""""", Farewell: Goodbye"

ss(3) = "Lions, Tigers, Bears,"

For Each s in ss
    Dim arr() As String: arr = CSVSplit(s)
    Dim i As Integer
    For i = 0 To UBound(arr)
        Call WriteLine("_________________________________________________")
        Call WriteLine(arr(i))
        Call WriteLine("_________________________________________________")
        Call WriteLine(vbNewLine)
    Next
Next

Выход :

      _________________________________________________
Panes
_________________________________________________


_________________________________________________
 Trains
_________________________________________________


_________________________________________________
 Automobiles
_________________________________________________


_________________________________________________
Wide
_________________________________________________


_________________________________________________
 He Said Tall, Skinny and round
_________________________________________________


_________________________________________________
 Narrow, but "manageable"
_________________________________________________


_________________________________________________
Speaker: Cindy
_________________________________________________


_________________________________________________
 Greeting: "Hello,
world"
_________________________________________________


_________________________________________________
 Farewell: Goodbye
_________________________________________________


_________________________________________________
Lions
_________________________________________________


_________________________________________________
 Tigers
_________________________________________________


_________________________________________________
 Bears
_________________________________________________


_________________________________________________

_________________________________________________


Другие вопросы по тегам