2008-11-25 2 views
5

Я пытаюсь использовать C# для разбора CSV. Я использовал регулярные выражения для поиска "," и прочитал строку, если мои подсчеты заголовков были равны числу совпадений.CSV Parsing

Теперь это не будет работать, если у меня есть значение как:

"a",""b","x","y"","c" 

то мой вывод:

'a' 
'"b' 
'x' 
'y"' 
'c' 

но то, что я хочу это:

'a' 
'"b","x","y"' 
'c' 

Есть любое регулярное выражение или любая другая логика, которую я могу использовать для этого?

+0

@ Matt: Не каждый родной Англоговорящий. Не знаю, что вызвало редактирование мании. Я вернул его обратно к версии, которая отражает первоначальное намерение, поскольку значение вопроса начало ухудшаться. – Tomalak 2008-11-25 08:33:49

+0

@xyz: Извините за анархические изменения, которые были внесены в ваш вопрос без уважительной причины. Надеюсь, это подошло к концу. – Tomalak 2008-11-25 08:38:27

+1

Ваш CSV недействителен, он должен быть "a", "" "b" "," "x" "," "y" "", "c" – dalle 2008-11-25 09:12:55

ответ

1

Для того чтобы иметь синтаксический CSV-файл, любые двойные кавычки внутри значения необходимо как-то экранировать. Два стандартных способа сделать это - представить двойную цитату либо в виде двух двойных кавычек, либо двойную кавычку обратной косой черты. Это один из двух следующих форм:

""

Во второй форме ваша первая строка будет выглядеть следующим образом:

"а", "\" б \ ", \" x \ ", \" y \ "", "c"

Если ваша строка ввода не отформатирована против какого-то строгого формата, то у вас мало шансов успешно разобрать ее в автоматизированной среде.

+0

нет, я не думаю, что это правда. в своем примере, если вы предполагаете, что CSV действителен как можно дольше (а не просто сдаваться в части «,», b), тогда вы все равно сможете разобрать это. – nickf 2008-11-25 12:15:31

0

Ну, я не regex wiz, но я уверен, что у них есть ответ на это.

Процедурно это происходит через письмо. Установите переменную, например dontMatch, в FALSE.

Каждый раз, когда вы запускаете цитату, переключите dontMatch.

каждый раз, когда вы запускаете запятую, проверьте dontMatch. Если он ИСТИНА, игнорируйте запятую. Если это ЛОЖЬ, разделите запятую.

Это работает для примера, который вы даете, но логика, которую вы используете для кавычек, принципиально ошибочна - вы должны избегать их или использовать другой разделитель (например, одинарные кавычки) для установки основных котировок, кроме незначительных котировок.

Например,

"a", ""b", ""c", "d"", "e""

даст плохие результаты.

Это может быть исправлено с другим патчем. Вместо того, чтобы просто сохранять истинное ложное значение, вам нужно сопоставить кавычки.

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

-Adam

1

Если все значения гарантированно быть в кавычках, искать ценности, а не запятые:

("".*?""|"[^"]*") 

Это использует тот факт, что «самый ранний самый длинный матч выигрывает "- сначала он ищет двойные кавычки и с более низким приоритетом для обычных котируемых значений.

Если вы не хотите, чтобы вшита котировка быть частью матча, использование:

"(".*?"|[^"]*)" 

и пойти на значение в матче группы 1.

Как я уже сказал: Предпосылкой для этого для работы хорошо сформированный ввод с гарантированными котировками или двойными кавычками вокруг каждого значения. Пустые значения должны быть указаны также! Хорошим побочным эффектом является то, что он не заботится о разделителе char. Запятые, TAB, полуколоны, пробелы, вы называете это. Все будет работать.

12

CSV, имея дело с вещами, такими как многострочные, процитированные, разные разделители * и т. Д. - может стать более сложным, чем вы могли бы подумать ... возможно, подумайте о предварительно прокатанном ответе? Я использую this, и он работает очень хорошо.

* = помните, что некоторые локалей [Tab] в качестве C в CSV ...

1

Там в часто цитируемый говоря:

Некоторые люди, когда они сталкиваются с проблемой , думаю, «Я знаю, я буду использовать регулярные выражения.» Теперь у них есть две проблемы. (Jamie Завински)

Учитывая, что нет никакого официального стандарта для CSV файлов (вместо этого есть большое количество слегка несовместимых стилей), вы должны убедиться, что вы реализуете подходит файлы, которые вы будете получать. Нет смысла внедрять что-либо более интересное, чем то, что вам нужно - и я уверен, что вам не нужны регулярные выражения.

Вот мой удар в простой метод для извлечения терминов - в основном, это петли через линию, ища запятые, отслеживание того, является ли текущий индекс в строке или нет:

public IEnumerable<string> SplitCSV(string line) 
    { 
     int index = 0; 
     int start = 0; 
     bool inString = false; 

     foreach (char c in line) 
     { 
      switch (c) 
      { 
       case '"': 
        inString = !inString; 
        break; 

       case ',': 
        if (!inString) 
        { 
         yield return line.Substring(start, index - start); 
         start = index + 1; 
        } 
        break; 
      } 
      index++; 
     } 

     if (start < index) 
      yield return line.Substring(start, index - start); 
    } 

Standard предостережением - непроверенный код, могут быть ошибки по очереди.

Ограничения

  • Кавычки вокруг значения не удаляются автоматически.
    Чтобы сделать это, добавьте чек непосредственно перед оператором yield return рядом с концом.

  • Одинарные кавычки не поддерживаются таким же образом, как двойные кавычки
    Вы можете добавить отдельный логический inSingleQuotedString, переименование существующего булевый inDoubleQuotedString и лечащих как один и тот же путь. (Вы не можете сделать существующее булевы делать двойную работу, потому что вам нужна строка до конца с теми же цитатами, который начал его.)

  • Пробелов не удаляются автоматически
    Некоторые инструментов вводить пробела вокруг запятых в CSV файлы для «симпатичного» файла; тогда становится трудно сказать преднамеренные пробелы от форматирования пробелов.

0

The Lumenworks CSV парсер (с открытым исходным кодом, бесплатно, но нуждается в Codeproject логин) на сегодняшний день является одним из лучших I» вы использовали. Это избавит вас от необходимости писать регулярное выражение и интуитивно понятно.

3

Я бы использовал FileHelpers, если бы был вами. Регулярные выражения прекрасно, но трудно читать, особенно если вы вернетесь через некоторое время, чтобы быстро исправить ситуацию.

Просто ради осуществления моего ума, быстро & грязного методики работы C#:

public static List<string> SplitCSV(string line) 
{ 
    if (string.IsNullOrEmpty(line)) 
     throw new ArgumentException(); 

    List<string> result = new List<string>(); 

    bool inQuote = false; 
    StringBuilder val = new StringBuilder(); 

    // parse line 
    foreach (var t in line.Split(',')) 
    { 
     int count = t.Count(c => c == '"'); 

     if (count > 2 && !inQuote) 
     { 
      inQuote = true; 
      val.Append(t); 
      val.Append(','); 
      continue; 
     } 

     if (count > 2 && inQuote) 
     { 
      inQuote = false; 
      val.Append(t); 
      result.Add(val.ToString()); 
      continue; 
     } 

     if (count == 2 && !inQuote) 
     { 
      result.Add(t); 
      continue; 
     } 

     if (count == 2 && inQuote) 
     { 
      val.Append(t); 
      val.Append(','); 
      continue; 
     } 
    } 

    // remove quotation 
    for (int i = 0; i < result.Count; i++) 
    { 
     string t = result[i]; 
     result[i] = t.Substring(1, t.Length - 2); 
    } 

    return result; 
} 
0

Я просто попробовать регулярное выражение в моих code..its отлично работают для отформатированного текста с цитатой .. .

, но интересно, если мы можем разобрать ниже значения по Regex ..

 
"First_Bat7679",""NAME","ENAME","FILE"","","","From: "DDD,_Ala%as"@sib.com" 

Ищу для результата, как:

 
'First_Bat7679' 
'"NAME","ENAME","FILE"' 
'' 
'' 
'From: "DDD,_Ala%as"@sib.com' 

Thanx

10

CSV является отличным примером для повторного использования кода - Независимо от того, который один из CSV парсеры вы выбираете, не выбирают самостоятельно. Stop Rolling your own CSV parser

1

Попробуйте CsvHelper (библиотека, которую я поддерживаю) или FastCsvReader. Оба работают хорошо. CsvHelper тоже пишет. Как все говорили, не сворачивайте себя. : P

1

FileHelpers поддерживает многострочные поля.

Вы можете разобрать файлы, подобные этим:

a,"line 1 
line 2 
line 3" 
b,"line 1 
line 2 
line 3" 

Вот тип данных декларации:

[DelimitedRecord(",")] 
public class MyRecord 
{ 
public string field1; 
[FieldQuoted('"', QuoteMode.OptionalForRead, MultilineMode.AllowForRead)] 
public string field2; 
} 

Здесь использование:

static void Main() 
{ 
FileHelperEngine engine = new FileHelperEngine(typeof(MyRecord)); 
MyRecord[] res = engine.ReadFile("file.csv");  
} 
Смежные вопросы