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-файл отлично действует в соответствии с приведенными выше правилами.

Я также прекрасно использую несколько регулярных выражений, если один из них затруднен. Но мне нравится избегать использования стандартных операций 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

5

Я бы не стал писать свой собственный синтаксический анализатор csv там, где есть много дел, которые выполняют эту работу за вас.

+0

Я предпочитаю не устанавливать сторонние библиотеки, если доступно простое решение. Но я рассмотрю встроенный Microsoft.VisualBasic.FileIO.TextFieldParser, который упоминается во второй ссылке. –

0

Вы можете использовать класс TextFieldParser, который встроен в .NET framework.

Для того, чтобы использовать этот класс в приложении C# вы должны добавить ссылку на Microsoft.VisualBasic.dll по следующему адресу (если вы сделали установку настроек по умолчанию)

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

Теперь в вашем C# класса есть ниже используя оператор:

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 Спасибо! Я действительно боялся, что этот ответ привлечет внимание из-за страха, что он был бы забыт, чтобы быть регулярным. По крайней мере, сейчас он может выдержать пять таких голосов, не отрицая репутации. :) –

Смежные вопросы