2016-08-29 12 views
0

Я знаю, что данные должны быть правильными. У меня нет контроля над данными, и мой босс просто собирается сказать мне, что мне нужно выяснить способ справиться с чужой ошибкой. Поэтому, пожалуйста, не говорите мне, что это не моя проблема, что данные плохие, потому что это так.Как я могу разобраться с анализом данных csv bad?

Anywho, это то, что я смотрю на:

"Words","[email protected]","","4253","57574","FirstName","","LastName, MD","","","576JFJD","","1971","","Words","Address","SUITE "A"","City","State","Zip","Phone","","" 

Данные были вымыты из соображений конфиденциальности.

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

Я использую TextFieldParser в пространстве имен Microsoft.VisualBasic.FileIO с этими настройками:

  parser.HasFieldsEnclosedInQuotes = true; 
      parser.SetDelimiters(","); 
      parser.TextFieldType = FieldType.Delimited; 

Ошибка является

MalformedLineException: Line 9871 cannot be parsed using the current delimiters.

Я хотел бы, чтобы вычистить данные каким-то образом на счет для этого, но я не уверен, как это сделать. Или, может быть, есть способ просто пропустить эту строку? Хотя я подозреваю, что мои более высокие взлеты не одобряют меня, просто пропуская данные, которые нам могут понадобиться.

+0

Вы пытались избежать проблемных цитат? – itsme86

+0

@ itsme86 убегает от них каким образом? –

+2

Пропустите неправильные строки, запишите их в файл, который периодически получает исправления вручную и повторно запускается.Надеюсь, не будет так много плохих строк, что это утомительно. – Kevin

ответ

2

Если вы только пытаетесь чтобы избавиться от паразитных " знаков в вашем CSV, вы можете использовать следующее регулярное выражение, чтобы найти их и заменить их '

String sourcestring = "source string to match with pattern"; 
String matchpattern = @"(?<!^|,)""(?!(,|$))"; 
String replacementpattern = @"$1'"; 
Console.WriteLine(Regex.Replace(sourcestring,matchpattern,replacementpattern,RegexOptions.Multiline)); 

Объяснение:

@"(?<!^|,)""(?!(,|$))"; найдет будет найти ", не предшествует началу строки, или , и что не следует в конце строки или ,

+0

Спасибо, это именно то, что мне нужно. –

1

Я должен был сделать это раньше,

Первым шагом для анализа данных с использованием string.split(',')

Следующим шагом является объединение сегментов, которые принадлежат вместе.

То, что я в основном сделал

  • сделать новый список, представляющий объединенные строки
  • , если строка начинается с цитаты, толкать его на новый список
  • если она не начинается с цитата, добавьте его к последней строке в списке
  • Bonus: бросать исключения, когда строка заканчивается цитатой, но следующий не начинается с цитатой

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

1

В ядре CSV's file format каждая строка представляет собой строку, каждая ячейка в этой строке разделяется запятой. В вашем случае ваш формат также содержит (очень неудачное) условие, что запятые внутри пары кавычек не считаются разделителями и являются частью данных. Я говорю очень неудачно, потому что неуместная кавычка влияет на всю остальную часть строки, а так как кавычки в стандартном ASCII не различают открытые и закрытые, на самом деле вы ничего не можете сделать, чтобы оправиться от этого, не зная первоначального намерения.

То есть, когда вы войдете сообщение таким образом, что человек, который делает знать первоначальное намерение (человек, который обеспечил данные) можно посмотреть на файл и исправить ошибку:

if (parse_line(line, &data)) { 
    // save the data 
} else { 
    // log the error 
    fprintf(&stderr, "Bad line: %s", line); 
} 

И поскольку ваши кавычки не ускользают от строк новой строки, вы можете продолжить работу со следующей строкой после запуска этой ошибки.

ADDENDUM: И если у вашей компании есть выбор (т. Е. Ваши данные сериализуются инструментом компании), не используйте CSV. Используйте что-то вроде XML или JSON с гораздо более четко определенным механизмом синтаксического анализа.

2

Я не знаком с TextFieldParser. Однако с CsvHelper, вы можете добавить пользовательский обработчик для недействительных данных:

var config = new CsvConfiguration(); 
config.IgnoreReadingExceptions = true; 
config.ReadingExceptionCallback += (e, row) => 
{ 
    // you can add some custom patching here if possible 
    // or, save the line numbers and add/edit them manually later. 
}; 

using(var file = File.OpenRead(".csv")) 
using(var reader = new CsvReader(reader, config)) 
{ 
    reader.GetRecords<YourDtoClass>(); 
} 
1

Мое единственное дополнение к тому, что говорит все (потому что мы все были там), чтобы попытаться, чтобы попытаться исправить каждую новую проблему, с которой сталкиваются с кодом. Есть некоторые достойные строки REGEX https://www.google.com/?ion=1&espv=2#q=c-sharp+regex+csv+clean или вы можете вручную исправить вещи, используя String.Replace (String.Replace ("\" \ "\" "," "). Замените (" \ "\", ""). ("\" ,, "," \ ",") или такие). В конце концов, поскольку вы обнаруживаете и находите способы исправления все большего числа ошибок, ваш уровень восстановления вручную будет практически сведен к минимуму (большинство ваших плохих данных, скорее всего, будут получены из-за подобных ошибок). Ура!

PS - Идея-иш (это было в то время - логика может нужду некоторых настроек, как я пишу по памяти), но вы получите суть:

public string[] parseCSVWithQuotes(string csvLine,int expectedNumberOfDataPoints) 
    { 
     string ret = ""; 
     string thisChar = ""; 
     string lastChar = ""; 
     bool needleDown = true; 
     for(int i = 0; i < csvLine.Length; i++) 
     { 
      thisChar = csvLine.Substring(i, 1); 
      if (thisChar == "'"&&lastChar!="'") 
       needleDown = needleDown == true ? false : true;//when needleDown = true, characters are treated literally 
      if (thisChar == ","&&lastChar!=",") { 
       if (needleDown) 
       { 
        ret += "|";//convert literal comma to pipe so it doesn't cause another break on split 
       }else 
       { 
        ret += ",";//break on split is intended because the comma is outside the single quote 
       } 
      } 
      if (!needleDown && (thisChar == "\"" || thisChar == "*")) {//repeat for any undesired character or use RegEx 
                     //do not add -- this eliminates any undesired characters outside single quotes 
      } 
      else 
      { 
       if ((lastChar == "'" || lastChar == "\"" || lastChar == ",") && thisChar == lastChar) 
       { 
        //do not add - this eliminates double characters 
       }else 
       { 
        ret += thisChar; 
        lastChar = thisChar; 
        //this character is not an undesired character, is no a double, is valid. 
       } 
      } 
     } 
     //we've cleaned as best we can 
     string[] parts = ret.Split(','); 
     if(parts.Length==expectedNumberOfDataPoints){ 
     for(int i = 0; i < parts.Length; i++) 
     { 
      //go back and replace the temporary pipe with the literal comma AFTER split 
      parts[i] = parts[i].Replace("|", ","); 
     } 

     return parts; 
     }else{ 
      //save ret to bad CSV log 
      return null; 
     } 
    } 
+0

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

0

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

Это то, что я сделал:

For each character on a line of input. 
1. when outside of a string meeting a comma => all of the previous string (which can be empty) is a valid token. 
2. when outside of a sting meeting anything but a comma or a quote => now you have a real problem, unquoted tekst => handle as you see fit. 
3. when outside of a string meeing a quote => found a start of string. 
4. when inside of a string meeting a comma => accept the comma as part of the string. 
5. when inside of the string meeting a qoute => trouble starts here, mark this point. 
    6. continue and when meeting a comma (skipping white space if desired) close the string, 'unread' the comma and continue. (than will bring you to point 1.) 
    7. or continue and when meeting a quote -> obviously, what was read must be part of the string, add it to the string, 'unread' the quote and continue. (that will you bring to point 5) 
    8. or continue and find an whitespace, then End Of Line ('\n') -> the last qoute must be the closing quote. accept the string as a value. 
    9. or continue and fine non-whitespace, then End Of Line. -> now you have a real problem, you have the start of a string but it is not closed -> handle the error as you see fit. 

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

С потоком строк, полученных от входной линии, вы можете построить «чистую» линию .csv и таким образом создать буфер принятых и очищенных входных данных, которые вы можете использовать в своем уже существующем коде.

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

  • Нет связанных вопросов^_^