Я просматриваю параметры разделенного файла (например, CSV, вкладка и т.д.), основанные на MS-стеке в целом и .net. Единственная технология, которую я исключаю, - это SSIS, потому что я уже знаю, что она не удовлетворит мои потребности.
Итак, мои параметры выглядят следующим образом:
- Regex.Split
- TextFieldParser
- OLEDB CSV Parser
У меня есть два критерия, которые я должен выполнить. Во-первых, учитывая следующий файл, который содержит две логические строки данных (и пять физических строк):
101, Bob, "Keeps his house ""clean"".
Needs to work on laundry."
102, Amy, "Brilliant.
Driven.
Diligent."
Анализируемые результаты должны приводить к двум логическим "строкам", состоящим из трех строк (или столбцов). Третья строка строки/столбца должна сохранять символы новой строки! Говоря иначе, анализатор должен распознавать, когда строки "продолжают" на следующую физическую строку из-за "незакрытого" текстового классификатора.
Второй критерий заключается в том, что разделитель и текстовый определитель должны быть настраиваемыми для каждого файла. Вот две строки, взятые из разных файлов, которые я должен разбирать:
var first = @"""This"",""Is,A,Record"",""That """"Cannot"""", they say,"","""",,""be"",rightly,""parsed"",at all";
var second = @"~This~|~Is|A|Record~|~ThatCannot~|~be~|~parsed~|at all";
Собственный синтаксический анализ строки "first" будет выглядеть следующим образом:
- Это
- Есть, А, запись
- То, что "не может", говорят,
- _
- _
- будет
- правильно
- разобран
- вообще
"_" просто означает, что был захвачен пробел - я не хочу, чтобы появился литерал.
Можно сделать одно важное предположение о анализируемых плоских файлах: будет фиксированное количество столбцов на файл.
Теперь для погружения в технические параметры.
REGEX
Во-первых, многие респонденты комментируют, что регулярное выражение "не лучший способ" для достижения цели. Однако я нашел комментатор который предложил превосходное регулярное выражение CSV:
var regex = @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))";
var Regex.Split(first, regex).Dump();
Результаты, примененные к строке "first", весьма замечательны:
- "This"
- "Есть, A, запись"
- "Это" "Не могу", говорят они, "
- ""
- _
- "быть"
- правильно
- "разобранный"
- вообще
Было бы неплохо, если бы кавычки были очищены, но я могу легко справиться с этим как шаг после процесса. В противном случае этот подход может использоваться для синтаксического анализа строк выборки "первым" и "вторым" при условии, что регулярное выражение модифицировано для символов тильды и труб соответственно. Отлично!
Но реальная проблема относится к многострочным критериям. Прежде чем регулярное выражение может быть применено к строке, я должен прочитать полную логическую "строку" из файла. К сожалению, я не знаю, сколько физических строк нужно прочитать для завершения логической строки, если у меня нет регулярного выражения/конечного автомата.
Итак, это становится проблемой "курица и яйцо". Моим лучшим вариантом было бы прочитать весь файл в памяти как одну гигантскую строку, и пусть регулярное выражение будет сортировать несколько строк (я не проверял, может ли это обработать вышеописанное выражение). Если у меня 10-гигабайтный файл, это может быть немного опасно.
В следующий раз.
TextFieldParser
Три строки кода сделают проблему с этой возможностью очевидной:
var reader = new Microsoft.VisualBasic.FileIO.TextFieldParser(stream);
reader.Delimiters = new string[] { @"|" };
reader.HasFieldsEnclosedInQuotes = true;
Конфигурация Delimiters выглядит неплохо. Однако "HasFieldsEnclosedInQuotes" - это "игра". Я ошеломлен тем, что разделители произвольно конфигурируются, но, напротив, у меня нет другого параметра выбора, кроме котировок. Помните, мне нужна настраиваемость над спецификатором текста. Итак, если кто-то не знает трюк конфигурации TextFieldParser, это игра.
OLEDB
Коллега говорит мне, что этот вариант имеет два основных недостатка. Во-первых, он имеет ужасную производительность для больших (например, 10-гигабайтных) файлов. Во-вторых, поэтому мне говорят, что он предпочел типы данных ввода данных, а не позволял вам указывать. Нехорошо.
HELP
Поэтому я хотел бы знать факты, в которых я ошибался (если они есть), и другие варианты, которые я пропустил. Возможно, кто-то знает способ для присяжных - TextFieldParser использовать произвольный разделитель. И, возможно, OLEDB разрешил указанные проблемы (или, возможно, никогда их не видел?).
Что вы говорите?