2012-06-29 4 views
0

CSV 파일에서 개별 필드를 추출하는 Regex를 작성하려고합니다. 예를 들어CSV를 파싱하기위한 정규식

, CSV 파일에서 다음 줄을 주어진 경우 :

123, Bob ,Bob, " Foo Bar ", "a, ""b"", c" 

합니다 (단일 따옴표없이 를) 다음과 같은 결과를 제공해야합니다 : 선도하는 것을

'123' 
'Bob' 
'Bob' 
' Foo Bar ' 
'a, "b", c' 

주 뒷부분의 공백은 따옴표 안에있는 것이 아니라면 잘라야합니다.

나는 닫는 따옴표가 일치하지 않는 열린 따옴표와 같은 잘못된 CSV 행에 대해 걱정하지 않습니다. 위의 규칙에 따라 CSV 파일이 완벽하게 유효하다고 가정 할 수 있습니다.

하나의 사람이 어려운 경우 Regexes를 여러 개 사용하는 것으로도 문제가 없습니다. 그러나 간단하고 짧지 않다면 표준 C# 연산을 사용하지 않는 것이 좋습니다. (나는 많은 코드를 작성하는 것을 끝내기를 원하지 않는다.)

그래서, 어떤 제안이라도?

+0

왜 정규식? 당신은 그것을 사용해야 만합니까? – gdoron

+1

CSV가 완전하게 유효하면 따옴표 붙은 필드에 줄 바꿈이 있습니다. – Joey

+0

"split"방법이이 경우에 더 적절하다고 생각합니다. –

답변

1

이 잘 많은 개는와 정규 표현식에와 오류 possiable있다 ... 나를 위해 속임수를 썼는지 다음 코드를 시도하고 달콤한 간단

Using Reader As New Microsoft.VisualBasic.FileIO.TextFieldParser("C:\MyFile.csv") 

Reader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited 

Dim MyDelimeters(0 To 0) As String 
Reader.HasFieldsEnclosedInQuotes = False 
Reader.SetDelimiters(","c) 

Dim currentRow As String() 
While Not Reader.EndOfData 
    Try 
     currentRow = Reader.ReadFields() 
     Dim currentField As String 
     For Each currentField In currentRow 
      MsgBox(currentField) 
     Next 
    Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException 
     MsgBox("Line " & ex.Message & 
     "is not valid and will be skipped.") 
    End Try 
End While 
End Using 

편리한 것으로 발견되면 답변으로 표시 ...

동일을 참조하십시오 implementation 여기 ,,,

+0

C#을 사용하고 있는데 Microsoft.VisualBasic.FileIO 네임 스페이스를 찾을 수 없습니다. 가져올 참조가 있습니까? –

+0

이 코드를 C#으로 변환하면 작동합니다 ... –

+0

C# "using System.IO;"를 추가해야합니다. 이렇게하면 독자와 작가 및 파일 액세스가 제공됩니다. – marcmiller2007

0

.NET 프레임 워크에 내장 된 TextFieldParser 클래스를 사용할 수 있습니다. 다음 위치에서 Microsoft.VisualBasic.dll의 참조를 추가해야합니다 당신의 C# 응용 프로그램에서이 클래스를 사용하기 위해

당신의 C# 클래스 지금

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Microsoft.VisualBasic.dll 

아래있다 (당신이 기본 설정으로 설치 한 가정) using 문 :

using Microsoft.VisualBasic.FileIO 
1

는 그 정규식이 "오른쪽"대답하지 동의하지만, 문제가 무엇을 요구하고 나는 좋은 정규식 도전을 좋아한다.

아래 패턴은 내 standard CSV parsing regex의 수정 된 버전으로 공백을 제거하고 요청한대로 CSV가 완벽하다고 가정합니다. 문제의 유일한 부분은 이스케이프/두배로 된 따옴표를 제거하지 않는다는 것입니다. 따옴표를 이스케이프 이스케이프 해제하는 예제는 패턴 뒤에 제공됩니다.이 각각의 비어 있지 않은 라인/레코드의 일치를 반환합니다 아래에 하나 개 이상의 라인/CSV 파일/스트림의 기록은 정규 표현식에 전달됩니다


. 각 일치 항목에는 캡처 된 값이 해당 라인/레코드에 포함 된 Value이라는 캡처 그룹이 포함됩니다.


여기 주석 패턴입니다 (그것을 on Regexstorm.net 테스트) :

(?<=\r|\n|^)(?!\r|\n|$)      // Records start at the beginning of line (line must not be empty) 
(?:           // Group for each value and a following comma or end of line (EOL) - required for quantifier (+?) 
    [^\S\r\n]*         // Removes leading spaces 
    (?:           // Group for matching one of the value formats before a comma or EOL 
    "(?<Value>(?:[^"]|"")*)"|     // Quoted value -or- 
    (?<Value>[^,\r\n]+)|      // Unquoted/open ended quoted value -or- 
    (?<Value>)        // Empty value before comma (before EOL is excluded by "+?" quantifier later) 
) 
    [^\S\r\n]*         // Removes trailing spaces 
    (?:,|(?=\r|\n|$))       // The value format matched must be followed by a comma or EOL 
)+?           // Quantifier to match one or more values (non-greedy/as few as possible to prevent infinite empty values) 
(?:(?<=,)(?<Value>))?       // If the group of values above ended in a comma then add an empty value to the group of matched values 
(?:\r\n|\r|\n|$)        // Records end at EOL 


여기 모든 의견이나 공백없이 원시 패턴입니다.

(?<=\r|\n|^)(?!\r|\n|$)(?:[^\S\r\n]*(?:"(?<Value>(?:[^"]|"")*)"|(?<Value>[^,\r\n]+)|(?<Value>))[^\S\r\n]*(?:,|(?=\r|\n|$)))+?(?:(?<=,)(?<Value>))?(?:\r\n|\r|\n|$) 


는 그리고, 여기에 C#을 버전을 탈출합니다. 정규식 패턴을 사용하는 방법에 대한

String CSVPattern= 
    @"(?<=\r|\n|^)(?!\r|\n|$)" + 
    @"(?:" + 
     @"[^\S\r\n]*" + 
     @"(?:" + 
      @"""(?<Value>(?:[^""]|"""")*)""|" + 
      @"(?<Value>[^,\r\n]+)|" + 
      @"(?<Value>)" + 
     @")" + 
     @"[^\S\r\n]*" + 
     @"(?:,|(?=\r|\n|$))" + 
    @")+?" + 
    @"(?:(?<=,)(?<Value>))?" + 
    @"(?:\r\n|\r|\n|$)"; 


예는 (물론,이 패턴으로 대체 할 수있는 원래의 패턴) 비슷한 질문 here에 내 대답에 발견, 또는 C# pad here, 또는 here에 할 수 있습니다.

참고 : 위 예제는 아래와 같이 따옴표를 undoubling/이스케이프 취소에 대한 논리를 포함 :

if (Capture.Length == 0 || Capture.Index == Record.Index || Record.Value[Capture.Index - Record.Index - 1] != '\"') 
{ 
    // No need to unescape/undouble quotes if the value is empty, the value starts 
    // at the beginning of the record, or the character before the value is not a 
    // quote (not a quoted value) 
    Console.WriteLine(Capture.Value); 
} 
else 
{ 
    // The character preceding this value is a quote 
    // so we need to unescape/undouble any embedded quotes 
    Console.WriteLine(Capture.Value.Replace("\"\"", "\"")); 
} 
+1

나는 거대한 정규 표현식에 넣은 작업량에 +1을 줄 것이다! : P –

+0

@SF Lee 고마워! 나는 실제로이 답변을 두려움에서 벗어나면 정규 표현식에 대한 망각에 투표하게 될 것입니다. 적어도 이제는 평판에 부정적인 영향을 미치지 않으면 서 5 개의 투표를 견뎌 낼 수 있습니다. :) –