2017-12-19 2 views
0

따옴표 및 추가 따옴표 안에하는 CSV 읽기 현재 구분 기호를 사용하여 전달할 수 없습니다. 유효하지 않으며 건너 뜁니다. 처음에는 쉼표가 문제라고 생각했지만 문제는 따옴표 안에 인용 부호가있는 것 같습니다.내가 CSV 파일이처럼 보이는이

아이디어를 읽는 방법?

추신. 내 코드가 일반적으로 직면하는 파일에는 인용 부호 안에 따옴표가 없으므로 파일을 읽는 빠르고 안정적이며 일반적인 방법을 찾고 있습니다. 정규 표현식은 내가 읽은 것에서부터 제 목적을 위해 매우 무겁습니다.

+0

파일을 큰 따옴표로 다시 써서'' "'로 쓸 수 있습니까? 큰 따옴표가있는 항목은 항상 줄의 마지막 항목입니까? 다른 필드에 쉼표가 있습니까? –

+1

파일에 잘못된 csv가 있습니다. 그 난장판을 고칠 수 있니? 아니면 파싱해야합니까? –

+0

구분 기호가 다른 '필드'에 나타나지 않는 세미콜론, 파이프 또는 다른 문자로 구성되도록 'CSV'파일을 변경할 수 있습니까 – Mych

답변

0

이 파일에는 유효하지 않은 CSV가 들어 있으며 일반적으로 구문 분석 할 수 없습니다. 그래서 "엉망"의 근원을 고쳐야합니다. Catch에서

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 

전화를 : 당신은 당신이 그것을 해결하기 위해 시도하는 방법 쓸 수 있다고 할 수없는 경우,

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 데이터 형식이 잘못되어 있기 때문에, 당신이 ' 데이터를 수동으로 구문 분석해야합니다. 다행히도 두 필드 만 있고 첫 번째 필드에 잘못된 형식이 포함되어 있지 않으므로 쉼표의 첫 번째 인스턴스 색인을 가져 와서 그와 같은 필드를 구분하면됩니다. 여기

빠른 예입니다

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 파일을 읽고 쓸 수있는 오픈 소스 라이브러리 - 당신의 CSV

당신은 Cinchoo ETL으로 시도 할 수
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

관련 문제