2017-12-19 25 views
0

私はこのように見ているCSVファイルを持っているの内側、とCSVを読む:二重引用符や余分な引用符

"Name1", "A test, which "fails" all the time" 
"Name2", "A test, which "fails" all the time" 
"Name3", "A test, which "fails" all the time" 

私のコードは次のとおりです。

Using parser As New FileIO.TextFieldParser(filepath) 
     parser.Delimiters = New String() {","} 
     parser.HasFieldsEnclosedInQuotes = True 
     parser.TrimWhiteSpace = False 
     Dim currentRow As String() 
     While Not parser.EndOfData 
      Try 
       currentRow = parser.ReadFields() 

      Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException 
       MsgBox("Line " & ex.Message & 
       "is not valid and will be skipped.") 
      Finally 

      End Try 

     End While 
    End Using 

私が手にエラーが1行目であります現在のデリミタを使用して渡すことはできません。有効ではなく、スキップされます。 最初はカンマが問題だと思っていましたが、引用符の中に引用符があるように見えます

どのように読むべきですか?

PS。私のコードが通常直面しているファイルは、引用符の中に引用符がないので、ファイルを読むための高速で信頼性の高い一般的な方法を探しています。 Regexは私が読んだところから、私の目的のために非常に重いです。

+0

ファイルを二重引用符で '' "'と正しく書き直すことができますか?二重引用符を持つ項目は、常に行の最後の項目ですか?他のフィールドにカンマが入っていますか? –

+1

ファイルに無効なcsvが含まれています。あなたはその混乱を修正できますか、それとも解析する必要がありますか? –

+0

区切り文字がセミコロン、パイプ、または他のフィールドに表示されない他の文字になるように 'CSV'ファイルを変更できます – Mych

答えて

0

このファイルには無効なCSVが含まれており、通常は解析できません。だからあなたは "混乱"の原因を修正する必要があります。しかし、あなたはそれを修正しようとするメソッドを書くことができることを行うことができない場合:

Function FixRowFieldsQuoteIssue(parser As TextFieldParser) As String() 
    If Not parser.HasFieldsEnclosedInQuotes Then Return Nothing 'method fixes quote issue 

    Dim errorLine As String = parser.ErrorLine 
    If String.IsNullOrWhiteSpace(errorLine) Then Return Nothing ' empty line no quote issue 

    errorLine = errorLine.Trim() 
    If Not errorLine.StartsWith("""") Then Return Nothing ' must start with quote otherwise fix not supported 

    Dim lineFields As New List(Of String) 
    Dim insideField As Boolean = False 
    Dim currentField As New List(Of Char) 

    For i As Int32 = 0 To errorLine.Length - 1 
     Dim c As Char = errorLine(i) 
     Dim isDelimiter = parser.Delimiters.Contains(c) 
     Dim isQuote = c = """" 

     If insideField Then 
      If isQuote Then 
       If i = errorLine.Length - 1 OrElse 
        parser.Delimiters.Contains(errorLine(i + 1)) Then 
        ' delimiter follows, this is a valid end field quote 
        ' can be improved by skipping spaces until delimiter 
        insideField = False 
        lineFields.Add(String.Concat(currentField)) 
        currentField = New List(Of Char) 
       Else 
        ' next char not a delimiter, this is invalid 
        ' add this quote to regular field-chars to fix it 
        currentField.Add(c) 
       End If 
      Else 
       ' regular char, add it to the current field chars 
       currentField.Add(c) 
      End If 
     ElseIf isQuote Then 
      insideField = True 
     End If 
    Next 

    Return lineFields.ToArray() 
End Function 

Catchからそれを呼び出します。

Dim allRowFields As New List(Of String()) 

Using parser As New FileIO.TextFieldParser("filePath") 
    parser.Delimiters = New String() {","} 
    parser.HasFieldsEnclosedInQuotes = True 
    parser.TrimWhiteSpace = False 

    While Not parser.EndOfData 
     Try 
      Dim currentRowFields As String() = parser.ReadFields() 
      allRowFields.Add(currentRowFields) 
     Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException 
      Dim fixedFields As String() = FixRowFieldsQuoteIssue(parser) 
      If fixedFields IsNot Nothing Then 
       allRowFields.Add(fixedFields) 
      Else 
       MsgBox("Line " & ex.Message & "Is Not valid And will be skipped.") 
      End If 
     End Try 
    End While 
End Using 
+0

面白いアイデア。私はそれをテストして知らせます – Nianios

0

CSVデータが正しくフォーマットされているので、あなたを」手動でデータを解析する必要があります。幸いなことに、フィールドが2つしかなく、最初のフィールドに無効な書式が含まれていないので、カンマの最初のインスタンスのインデックスを取得し、そのようなフィールドを区切るだけで、これを行うことができます。

Private Function Parse_CSV(ByVal csv As String) As DataTable 
    'Create a new instance of a DataTable and create the two columns 
    Dim dt As DataTable = New DataTable("CSV") 
    dt.Columns.AddRange({New DataColumn("Column1"), New DataColumn("Column2")}) 

    'Placeholder variable for the separator 
    Dim separator As Integer = -1 

    'Iterate through each line in the data 
    For Each line As String In csv.Split({Environment.NewLine}, StringSplitOptions.None) 
    'Get the first instance of a comma 
    separator = line.IndexOf(","c) 

    'Check to make sure the data has two fields 
    If separator = -1 Then 
     Throw New MissingFieldException("The current line is missing a separator: " & line) 
    ElseIf separator = line.Length - 1 Then 
     Throw New MissingFieldException("The separator cannot appear at the end of the line, this is occuring at: " & line) 
    Else 
     'Add the two fields to the datatable(getting rid of the starting and ending quotes) 
     dt.Rows.Add({line.Substring(0, separator), line.Substring(separator + 2)}) 
    End If 
    Next 

    'Return the data 
    Return dt 
End Function 

フィドル:Live Demo

+0

このファイルはデモです。実際のファイルは120列ではるかに大きくなります。また、これは私が解析しなければならない多くのファイルの一つです – Nianios

0

これは、2列にあなたのCSVを分割し、内側にあなたの引用符を残すだろう。ここ

は簡単な例です。 CSVファイルを読み書きするためのオープンソースライブラリ - はあなたがCinchoo ETLを試みることができるあなたのCSV

Dim xdata As New List(Of KeyValuePair(Of String, String)) 
Dim xline As String = """Name3"", ""A test, which ""fails"" all the time""" 
Dim FirstCol As Integer = Strings.InStr(xline, ",") 
xdata.Add(New KeyValuePair(Of String, String)(Strings.Left(xline, FirstCol - 1).Replace(Chr(34), ""), Strings.Mid(xline, FirstCol + 2).Remove(0, 1).Remove(Strings.Mid(xline, FirstCol + 2).Remove(0, 1).Length - 1, 1))) 
0

の1行でXLINEを交換してください。あなたが方法1ファイル

を解析することができる方法の

カップル:インデックスによるアクセス(何の列名が指定されていないことにする)

using (var parser = new ChoCSVReader("NestedQuotes.csv")) 
{ 
    foreach (dynamic x in parser) 
     Console.WriteLine(x[0] + "-" + x[1]); 
} 
:列名

using (var parser = new ChoCSVReader("NestedQuotes.csv") 
    .WithFields("name", "desc") 
    ) 
{ 
    foreach (dynamic x in parser) 
     Console.WriteLine(x.name + "-" + x.desc); 
} 

方法2を指定します

希望します。

詳細については、下記のcodeprojectの記事をお読みください。 https://www.codeproject.com/Articles/1145337/Cinchoo-ETL-CSV-Reader

関連する問題