2015-02-23 5 views
2

Я пытаюсь разделить ввод CSV, используя следующее регулярное выражение:CSV Regex разделить отсутствует столбцы

(?:^|,)(?=[^"]|(")?)"?((?(1)[^"]*|[^,"]*))"?(?=,|$) 

линии/строку с данными ,a,b,c результатов в 3-х матчах:

  1. , б
  2. , с

Я теряю/пропускаю ,a, и я не могу понять, что нужно изменить.

Это похоже на работу с помощью опции Python: https://regex101.com/r/kW3pQ6/1

Любая идея, как это исправить для .NET?

Это может помочь:

(?:^|,)(?=[^"]|(")?)"?((?(1)[^"]*|[^,"]*))"?(?=,|$) 

Regular expression visualization

Debuggex Demo

+0

см. Csv для набора данных C# в google? почему вы используете регулярное выражение? – mybirthname

ответ

2

Почему бы не использовать пакет Csv NuGet, который принимает во внимание множество нюансов CSV разбора, что вы пытаетесь решить сейчас и другие, о которых вы не знаете, что вам нужно решить еще :-)

CsvHelper очень популярный пакет ОС:
https://www.nuget.org/packages/CsvHelper
https://github.com/JoshClose/CsvHelper

+0

Нет необходимости в внешней библиотеке для чего-то такого простого. Почему бы не использовать встроенный класс 'TextFieldParser'? – Neaox

+0

Синтаксический анализ Csv не всегда прост, есть много нюансов - поэтому библиотека существует. –

+0

«TextFieldParser» позаботился о каждом «нюансе», с которым я столкнулся. Единственное, с чем он не справляется, - это спецификаторы текста без кавычек («), которые в этом случае не являются проблемой. – Neaox

2

Как и другие предложили вам следует использовать класс, целью которого является разобрать строку CSV. Класс TextFieldParser встроен в .NET. Если у вас нет дополнительных требований, не упомянутых в вашем вопросе, его вероятность не нужна для использования внешней библиотеки.

using(MemoryStream stream = new MemoryStream()) 
using(StreamWriter writer = new StreamWriter(stream)) 
{ 
    writer.Write(s); 
    writer.Flush(); 
    stream.Position = 0; 

    using(TextFieldParser parser = new TextFieldParser(stream)){ 
     parser.TextFieldType = FieldType.Delimited; 
     parser.Delimiters = new string[] {","}; 
     parser.HasFieldsEnclosedInQuotes = true; 

     while(!parser.EndOfData){ //Loop through lines until we reach the end of the file 
      string[] fields = parser.ReadFields(); //This will contain your fields 
     } 
    } 
} 

https://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.textfieldparser%28v=vs.110%29.aspx

+0

Это не подходит, как при использовании регулярных выражений. +1 к вам –

+0

может быть проще просто прочитать весь файл, сохранить его в массиве строк и использовать разделитель символов в «,»? –

+1

TextFieldParser может читать из потока, файла или TextReader, который он не может читать напрямую из строкового или строкового массива, поэтому мы сначала загружаем строку в поток памяти. Поскольку строка/файл в формате CSV может иметь экранированные элементы, некоторые с кавычками некоторые без этого могут вызвать проблемы. TextFieldParser - это быстрый способ разбора строки CSV, при этом такие отклонения не отключаются. – Neaox

0

Да, я знаю, что регулярное выражение не является «правильным» ответом, но это вопрос, который задан, и мне нравится хорошая проблема с регулярным выражением.

Примечания: Хотя ниже решение, вероятно, может быть адаптированы для других регулярных выражений двигателей, используя его как есть будет требовать, чтобы ваш движок регулярных выражений трактуют multiple named capture groups using the same name одной группы захвата. (.NET делает это по умолчанию)


Когда несколько строк/записи в CSV-файл/поток (сопрягая RFC standard 4180) передаются в регулярном выражении ниже он будет возвращать матч для каждой непустой строки/записи , Каждое совпадение будет содержать группу захвата с именем Value, которая содержит зафиксированные значения в этой строке/записи (и, возможно, группу захвата OpenValue, если в конце строки/записи была открытая цитата).

Вот комментируемого шаблон (проверить это 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 (+?) 
    (?:           // Group for matching one of the value formats before a comma or EOL 
    "(?<Value>(?:[^"]|"")*)"|     // Quoted value -or- 
    (?<Value>(?!")[^,\r\n]+)|     // Unquoted value -or- 
    "(?<OpenValue>(?:[^"]|"")*)(?=\r|\n|$)| // Open ended quoted value -or- 
    (?<Value>)        // Empty value before comma (before EOL is excluded by "+?" quantifier later) 
) 
    (?:,|(?=\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|$)(?:(?:"(?<Value>(?:[^"]|"")*)"|(?<Value>(?!")[^,\r\n]+)|"(?<OpenValue>(?:[^"]|"")*)(?=\r|\n|$)|(?<Value>))(?:,|(?=\r|\n|$)))+?(?:(?<=,)(?<Value>))?(?:\r\n|\r|\n|$) 


Here is a visualization from Debuggex.com (захват группы, названные для ясности): Debuggex.com visualization

Примеры о том, как использовать шаблон регулярных выражений можно найти на мой ответ на аналогичный вопрос here, или на C# pad here или here ,

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