Работа с полями, содержащими неоткрытые двойные кавычки с TextFieldParser
Я пытаюсь импортировать CSV-файл с помощью TextFieldParser. Конкретный файл CSV вызывает у меня проблемы из-за его нестандартного форматирования. CSV, о котором идет речь, имеет свои поля, заключенные в двойные кавычки. Проблема появляется, когда существует дополнительный набор экранированные двойные кавычки внутри определенного поля.
вот упрощенный тестовый случай, который подчеркивает проблему. Фактические CSV-файлы, с которыми я имею дело, не все отформатированы одинаково и имеют десятки полей, любое из которых может содержать эти, возможно, сложные проблемы форматирования.
TextReader reader = new StringReader(""Row","Test String"n" +
""1","This is a test string. It is parsed correctly."n" +
""2","This is a test string with a comma, which is parsed correctly"n" +
""3","This is a test string with double ""double quotes"". It is parsed correctly"n" +
""4","This is a test string with 'single quotes'. It is parsed correctly"n" +
"5,This is a test string with fields that aren't enclosed in double quotes. It is parsed correctly.n" +
""6","This is a test string with single "double quotes". It can't be parsed."");
using (TextFieldParser parser = new TextFieldParser(reader))
{
parser.Delimiters = new[] { "," };
while (!parser.EndOfData)
{
string[] fields= parser.ReadFields();
Console.WriteLine("This line was parsed as:n{0},{1}",
fields[0], fields[1]);
}
}
есть ли в любом случае, чтобы правильно проанализировать CSV с этим типом форматирования с помощью TextFieldParser?
6 ответов
Я согласен с Советом Ханса Пассанта, что вы не несете ответственности за анализ искаженных данных. Однако, в соответствии с Принцип Робастности, кто-то столкнулся с этой ситуацией может попытаться обработать определенные типы искаженных данных. Код, который я написал ниже, работает над набором данных, указанным в вопросе. В основном он обнаруживает ошибку парсера на искаженной строке, определяет, является ли она двойной кавычкой, обернутой на основе первого символа, а затем разбивает/разбивает все перенос двойных кавычек вручную.
using (TextFieldParser parser = new TextFieldParser(reader))
{
parser.Delimiters = new[] { "," };
while (!parser.EndOfData)
{
string[] fields = null;
try
{
fields = parser.ReadFields();
}
catch (MalformedLineException ex)
{
if (parser.ErrorLine.StartsWith("\""))
{
var line = parser.ErrorLine.Substring(1, parser.ErrorLine.Length - 2);
fields = line.Split(new string[] { "\",\"" }, StringSplitOptions.None);
}
else
{
throw;
}
}
Console.WriteLine("This line was parsed as:\n{0},{1}", fields[0], fields[1]);
}
}
Я уверен, что можно состряпать патологический пример, когда это не удается (например, запятые, соседние с двойными кавычками в значении поля), но любые такие примеры, вероятно, будут непростимыми в самом строгом смысле, тогда как проблемная строка, данная в вопросе, расшифровывается, несмотря на то, что она искажена.
может быть проще просто сделать это вручную, и это, безусловно, даст вам больше контроля:
изменить: Для вашего уточненного примера я по-прежнему предлагаю вручную обрабатывать синтаксический анализ:
using System.IO;
string[] csvFile = File.ReadAllLines(pathToCsv);
foreach (string line in csvFile)
{
// get the first comma in the line
// everything before this index is the row number
// everything after is the row value
int firstCommaIndex = line.IndexOf(',');
//Note: SubString used here is (startIndex, length)
string row = line.Substring(0, firstCommaIndex+1);
string rowValue = line.Substring(firstCommaIndex+1).Trim();
Console.WriteLine("This line was parsed as:\n{0},{1}",
row, rowValue);
}
для общего CSV, который не допускает запятых в полях:
using System.IO;
string[] csvFile = File.ReadAllLines(pathToCsv);
foreach (string line in csvFile)
{
string[] fields = line.Split(',');
Console.WriteLine("This line was parsed as:\n{0},{1}",
fields[0], fields[1]);
}
Рабочего Раствора :
using (TextFieldParser csvReader = new TextFieldParser(csv_file_path))
{
csvReader.SetDelimiters(new string[] { "," });
csvReader.HasFieldsEnclosedInQuotes = false;
string[] colFields = csvReader.ReadFields();
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
for (i = 0; i < fieldData.Length; i++)
{
if (fieldData[i] == "")
{
fieldData[i] = null;
}
else
{
if (fieldData[i][0] == '"' && fieldData[i][fieldData[i].Length - 1] == '"')
{
fieldData[i] = fieldData[i].Substring(1, fieldData[i].Length - 2);
}
}
}
csvData.Rows.Add(fieldData);
}
}
Если вы не установили HasFieldsEnclosedInQuotes = true результирующий список столбцов будет больше, если данные содержат (,) запятая. например "На Col1","Столбец Col2","Кол3" "Test1", 100, " Test1, Test2" "Test2", 200, " Test22" Этот файл должен иметь 3 столбца, но при разборе вы получите 4 поля, что неправильно.
решение Джордана довольно хорошее, но оно делает неправильное предположение, что строка ошибки всегда будет начинаться с двойной кавычки. Моя строка ошибки была такой:
170,"CMS ALT",853,,,NON_MOVEX,COM,NULL,"2014-04-25","" 204 Route de Trays"
обратите внимание, что в последнем поле были дополнительные/неоткрытые двойные кавычки, но первое поле было в порядке. Так что решение Джордана не сработало. Вот мое модифицированное решение, основанное на Иорданском:
using(TextFieldParser parser = new TextFieldParser(new StringReader(csv))) {
parser.Delimiters = new [] {","};
while (!parser.EndOfData) {
string[] fields = null;
try {
fields = parser.ReadFields();
} catch (MalformedLineException ex) {
string errorLine = SafeTrim(parser.ErrorLine);
fields = errorLine.Split(',');
}
}
}
вы можете обрабатывать блок catch по-разному, но общая концепция отлично работает для меня.