Как я могу переформатировать файл CSV в формат Календаря Google? - PullRequest
4 голосов
/ 25 мая 2011

Так что после некоторых исследований я смог найти формат, который мне нужен, чтобы получить файл CSV в

Subject,Start Date,Start Time,End Date,End Time,All Day Event,Description,Location,Private

Проблема в том, что экспорт CSV, с которым я работаю, имеет неправильный формат или порядок, каков наилучший способ сбора этой информации? Вот немного моего источника.

Имя, Имя пользователя, Тип строки, Дата начала, Время начала, Время окончания, Дата окончания, Дата начала сегмента, Тип

"Smith, John J", jjs, Shift, 5/29 / 2011,9: 30,17: 30,5 / 29 / 2011,5 / 29/2011, Regular

"Smith, John J", jjs, Shift, 5/30 / 2011,13: 30,17: 30,5 / 30 / 2011,5 / 30/2011, Regular

    Dim Name As String = ""
    Dim UserName As String = ""

    Dim Data As String = """Smith, John J"",jj802b,Shift,5/29/2011,9:30,17:30,5/29/2011,5/29/2011,Transfer"

    For r As Integer = 1 To 10
        Name = Data.Substring(0, Data.LastIndexOf(""""))
        Data = Data.Remove(0, Data.LastIndexOf(""""))
        UserName = Data.Substring(Data.LastIndexOf(""""), ",")
    Next

Ответы [ 4 ]

3 голосов
/ 30 мая 2011

Ниже приводится решение

Dim Name As String = ""
Dim UserName As String = ""

Dim Data As String = """Smith, John J"",jj802b,Shift,5/29/2011,9:30,17:30,5/29/2011,5/29/2011,Transfer"

For r As Integer = 1 To 10
    Dim DataArr() As String = DecodeCSV(Data) 'Use DecodeCSV function to regex split the string 
    Name = DataArr(0) 'Get First item of array as Name
    UserName = DataArr(1)  'Get Second item of array as UserName 
Next

Отличный код для DecodeCSV от Tim

Public Shared Function DecodeCSV(ByVal strLine As String) As String()

    Dim strPattern As String
    Dim objMatch As Match

    ' build a pattern
    strPattern = "^" ' anchor to start of the string
    strPattern += "(?:""(?<value>(?:""""|[^""\f\r])*)""|(?<value>[^,\f\r""]*))"
    strPattern += "(?:,(?:[ \t]*""(?<value>(?:""""|[^""\f\r])*)""|(?<value>[^,\f\r""]*)))*"
    strPattern += "$" ' anchor to the end of the string

    ' get the match
    objMatch = Regex.Match(strLine, strPattern)

    ' if RegEx match was ok
    If objMatch.Success Then
        Dim objGroup As Group = objMatch.Groups("value")
        Dim intCount As Integer = objGroup.Captures.Count
        Dim arrOutput(intCount - 1) As String

        ' transfer data to array
        For i As Integer = 0 To intCount - 1
            Dim objCapture As Capture = objGroup.Captures.Item(i)
            arrOutput(i) = objCapture.Value

            ' replace double-escaped quotes
            arrOutput(i) = arrOutput(i).Replace("""""", """")
        Next

        ' return the array
        Return arrOutput
    Else
        Throw New ApplicationException("Bad CSV line: " & strLine)
    End If

End Function
2 голосов
/ 04 июня 2011

Это будет долго, так что держись со мной.

Перед началом я хотел бы отметить несколько вещей:

  • Во-первых, яm, используя TextFieldParser, который вы можете найти в пространстве имен FileIO, для работы с входным CSV.Это делает чтение файлов с разделителями намного проще, чем попытки справиться с регулярными выражениями и вашим собственным синтаксическим анализом и т. Д.
  • Другое - хранить наборы данных, которые я использую List(Of Dictionary(Of String, String)), или список словарей.которые связывают строки с другими строками.По сути, это мало чем отличается от схемы доступа DataTable, и если вам удобнее использовать эту конструкцию, вы можете использовать ее вместо этого.Список словарей вел себя точно так же и требовал гораздо меньших настроек, поэтому он используется здесь вместо него.

Я допускаю, что некоторые из них жестко запрограммированы, но если вам нужно обобщить процедуру,Вы можете перенести определенные аспекты в настройки приложения и / или лучше разложить функцию.Суть в том, чтобы дать вам общее представление.Код прокомментирован ниже:

    ' Create a text parser object
    Dim theParser As New FileIO.TextFieldParser("C:\Path\To\theInput.csv")

    ' Specify that fields are delimited by commas
    theParser.Delimiters = {","}

    ' Specify that strings containing the delimiter are wrapped by quotes
    theParser.HasFieldsEnclosedInQuotes = True

    ' Dimension containers for the field names and the list of data rows
    ' Initialize the field names with the first row r
    Dim theInputFields As String() = theParser.ReadFields(),
        theInputRows As New List(Of Dictionary(Of String, String))()

    ' While there is data to parse
    Do While Not theParser.EndOfData

        ' Dimension a counter and a row container
        Dim i As Integer = 0,
            theRow As New Dictionary(Of String, String)()

        ' For each field
        For Each value In theParser.ReadFields()

            ' Associate the value of that field for the row
            theRow(theInputFields(i)) = value

            ' Increment the count
            i += 1
        Next

        ' Add the row to the list
        theInputRows.Add(theRow)
    Loop

    ' Close the input file for reading
    theParser.Close()

    ' Dimension the list of output field names and a container for the list of formatted output rows
    Dim theOutputFields As New List(Of String) From {"Subject", "Start Date", "Start Time", "End Date", "End Time", "All Day Event", "Description", "Location", "Private"},
        theOutputRows As New List(Of Dictionary(Of String, String))()

    ' For each data row we've extracted from the CSV
    For Each theRow In theInputRows

        ' Dimension a new formatted row for the output
        Dim thisRow As New Dictionary(Of String, String)()

        ' For each field name of the output rows
        For Each theField In theOutputFields

            ' Dimension a container for the value of this field
            Dim theValue As String = String.Empty

            ' Specify ways to get the value of the field based on its name
            ' These are just examples; choose your own method for formatting the output
            Select Case theField

                Case "Subject"
                    ' Output a subject "[Row Type]: [Name]"
                    theValue = theRow("Row Type") & ": " & theRow("Name")

                Case "Description"
                    ' Output a description from the input field [Type]
                    theValue = theRow("Type")

                Case "Start Date", "Start Time", "End Date", "End Time"
                    ' Output the value of the field with a correlated name
                    theValue = theRow(theField)

                Case "All Day Event", "Private"
                    ' Output False by default (you might want to change the case for Private
                    theValue = "False"

                Case "Location"
                    ' Can probably be safely left empty unless you'd like a default value
            End Select

            ' Relate the value we've created to the column in this row
            thisRow(theField) = theValue
        Next

        ' Add the formatted row to the output data
        theOutputRows.Add(thisRow)
    Next

    ' Start building the first line by retriving the name of the first output field
    Dim theHeader As String = theOutputFields.First

    ' For each of the remaining output fields
    For Each theField In (From s In theOutputFields Skip 1)

        ' Append a comma and then the field name
        theHeader = theHeader & "," & theField
    Next

    ' Create a string builder to store the text for the output file, initialized with the header line and a line break
    Dim theOutput As New System.Text.StringBuilder(theHeader & vbNewLine)

    ' For each row in the formatted output rows
    For Each theRow In theOutputRows

        ' Dimension a container for this line of the file, beginning with the value of the column associated with the first output field
        Dim theLine As String = theRow(theOutputFields.First)

        ' Wrap the first value if necessary
        If theLine.Contains(",") Then theLine = """" & theLine & """"

        ' For each remaining output field
        For Each theField In (From s In theOutputFields Skip 1)

            ' Dereference and store the associated column value
            Dim theValue As String = theRow(theField)

            ' Add a comma and the value to the line, wrapped in quotations as needed
            theLine = theLine & "," & If(theValue.Contains(","), """" & theValue & """", theValue)
        Next

        ' Append the line to the output string
        theOutput.AppendLine(theLine)
    Next

    ' Write the formatted output to file
    IO.File.WriteAllText("C:\output.csv", theOutput.ToString)

Для чего стоит, использование ваших данных примера, казалось, привело к открытию выходного файла в OpenOffice.org Calc с использованием этого кода.Формат того, что вы хотите вывести для полей, остается на ваше усмотрение, поэтому измените соответствующий оператор Case в Select для этого, и удачного кодирования!

2 голосов
/ 04 июня 2011

В зависимости от точного содержимого и гарантии формата файла CSV, для скорости и простоты, иногда использование split на , является самым простым и быстрым способом анализа файла.Ваше имя col включает ,, который не является разделителем, что добавляет немного сложности, хотя обрабатывать этот случай все еще тривиально, предполагая, что имя всегда содержит 1 ,.

.разбирать файлы CSV, которые могут быть полезны.Предполагая, что вам не нужно обрабатывать все файлы, которые соответствуют спецификации CSV, я чувствую, что они излишни.С учетом всего сказанного вы можете использовать следующее регулярное выражение , чтобы легко проанализировать файл CSV с именованными группами для убеждения:

"(?<Name>[^"]+?)",(?<UserName>[^,]+?),(?<RowType>[^,]+?),(?<StartDate>[^,]+?),(?<StartTime>[^,]+?),(?<EndTime>[^,]+?),(?<EndDate>[^,]+?),(?<SegmentStartDate>[^,]+?),(?<Type>\w+)

Это создаст именованные группы захватакоторые затем можно использовать для вывода в новый CSV-файл следующим образом:

Dim ResultList As StringCollection = New StringCollection()
Try
    Dim RegexObj As New Regex("""(?<Name>[^""]+?)"",(?<UserName>[^,]+?),(?<RowType>[^,]+?),(?<StartDate>[^,]+?),(?<StartTime>[^,]+?),(?<EndTime>[^,]+?),(?<EndDate>[^,]+?),(?<SegmentStartDate>[^,]+?),(?<Type>\w+)", RegexOptions.IgnoreCase)
    Dim MatchResult As Match = RegexObj.Match(SubjectString)
    While MatchResult.Success
        'Append to new CSV file - MatchResult.Groups("groupname").Value

        'Name = MatchResult.Groups("Name").Value
        'Start Time = MatchResult.Groups("StartTime").Value         
        'End Time = MatchResult.Groups("EndTime").Value
        'Etc...
    End While
Catch ex As ArgumentException
    'Syntax error in the regular expression
End Try

См. Регулярные выражения .NET Framework в MSDN для получения дополнительной информации.

1 голос
/ 02 июня 2011

В этом ответе на аналогичный вопрос рекомендуется использовать класс VB TextFieldParser, который мне кажется более удачной идеей, чем использование собственного парсера csv.На первый взгляд, у вас есть обязательные поля данных, даты начала и окончания, остальные, кроме, вероятно, темы и / или описания, могут быть либо оставлены пустыми, либо заполнены значением по умолчанию / фиксированным значением ...

...