Адъ CSV
А напишите кто-нибудь табличку состояний CSV парсера? Т.е. последовательность символов, разделенных запятыми, в строках, разделенных \r или \r\n разбить на список списков строк. Если в строке должны быть служебные символы (т.е. запятая или \r \n) - строка обрамляется в кавычки, если внутри такой строки нужна кавычка - ставится две кавычки подряд.
На самом деле там немного сложнее, типа допустимо незначимые пробелы возле запятых, а значимыми их делают тоже через кавычки, управляющие символы <32 вроде тоже обязательно в кавычки, но это пофиг.
Вроде блин простая задачка, а каждый раз когда ее приходится делать - получаются на пару страниц конечные автоматы.
На самом деле там немного сложнее, типа допустимо незначимые пробелы возле запятых, а значимыми их делают тоже через кавычки, управляющие символы <32 вроде тоже обязательно в кавычки, но это пофиг.
Вроде блин простая задачка, а каждый раз когда ее приходится делать - получаются на пару страниц конечные автоматы.
no subject
Экспортирую из 2007 экселя в CSV. Он, зараза, и кавычки не ставит и служебные символы не эскейпит. С горя в XML начал экспортировать, а он угловые скобки html срезает.
Есть там кнопка "сделать чтоб работало" ?
no subject
no subject
Есть делиметер, допустим, запятая.
Поиск делиметера, по позициям - нарезка строки в список строк.
все, строка распаршена. Дальше по каждой подстроке уже убирание кавычек краевых, если они присутствуют, ну и байт стаффинг кавычек. Хотя на самом деле меня плющит, что вот делиметер внутри никаким байстаффингом не кодируется. То есть его просто тупо не может быть. Надо документ почитать про CSV, я не помню, как там по науке. Также и не помню как с \r\n быть по науке.
no subject
Поиск делимитера по позициям ломается на делимитерах внутри кавычек.
И обрабатываю я не одну строку а все строки подряд, потому что у меня может быть такое:
"test
test"
и это должно вернуться в виде одной строки внутри списка, с \r\n внутри
no subject
no subject
no subject
там кроме одного флага и значения предыдущего символа ничего не нужно
no subject
no subject
no subject
Вроде бы по стандарту, он должен игнорироваться, если около разделителей, а внутри строки недопустим.
no subject
Обработка пробелов - вообще не проблема.
no subject
no subject
no subject
quoted=0; prev_char=0; start_field(); while(c=getch()) { if (quoted) { if ('"' == c)) quoted = 0; else field_append_char(ch); } else { if ('"' == ch) { if ('"' == prev_char) { field_append_char(ch); quoted = 1; } else if (',' == prev_char) { quoted = 1; } else { report_error(); return; } } else if (',' == ch) { end_field(); start_field() } else { if ('"' == prev_char) { report_error(); return; } else { field_append_char(ch); } } } prev_char = ch; } if (quoted) { report_error(); return; } end_field()no subject
extract_line(Data) -> extract_line(Data, []). extract_line(Data, Accum) -> case extract_value(Data) of {Value, Rest} -> extract_line(Rest, [r(Value)|Accum]); {Rest} -> {r(Accum), Rest}; novalue when Accum =/= [] -> {r(Accum), []}; novalue -> noline end. extract_value([]) -> novalue; extract_value([$\r,$\n|Rest]) -> {Rest}; extract_value([$\n|Rest]) -> {Rest}; extract_value([$"|Rest]) -> extract_quoted(Rest, []); extract_value(Rest) -> extract_nonquoted(Rest, []). extract_nonquoted([$\n|_]=Rest, V) -> {V, Rest}; extract_nonquoted([$\r,$\n|_]=Rest, V) -> {V, Rest}; extract_nonquoted([$,|Rest], V) -> {V, Rest}; extract_nonquoted([C|Rest], V) -> extract_nonquoted(Rest, [C|V]); extract_nonquoted([], V) -> {V, []}. extract_quoted([$",$,|Rest], V) -> {V, Rest}; extract_quoted([$",$\r,$\n|Rest], V) -> {V, [$\n|Rest]}; extract_quoted([$",$\n|Rest], V) -> {V, [$\n|Rest]}; extract_quoted([$",$"|Rest], V) -> extract_quoted(Rest, [$"|V]); extract_quoted([$"], V) -> {V, []}; extract_quoted([$\r,$\n|Rest], V) -> extract_quoted(Rest, [$\n|V]); extract_quoted([C|Rest], V) -> extract_quoted(Rest, [C|V]); extract_quoted([], V) -> {V, []}.no subject
no subject
no subject
enum { ST_NOCHANGE, /* Pseudo-state */ ST_PLAIN, ST_QUOTED_VALUE, _ST_MAX } stateTable[_ST_MAX][256] = { [ST_PLAIN] = { [ '"' ] = ST_QUOTED_VALUE, ... }, [ST_QUOTED_VALUE] = { ... } };no subject
тогда для значения столбца и для текста целиком получаются следующие регулярные языки
V = (A\{',', 'eol', '"'})* + "(A\{'"'}+"")*"
S =((V,)*Veol)* = (V(, + eol))*
регулярный язык сводится к автомату. этот, если не ошибаюсь, к такому:
A\{',', 'eol', '"'} {'"'} {'eol', ','} 1 1 2 1 2 2 3 2 3 err 2 1из умолчаний тут нельзя иметь кавычки как символы внутри значения не заключенного в кавычки, и после окончания кавычек должен идти разделитель значений. ну и плюс никакие колбеки нигде не вызываются, поэтому например неразличимы делимитеры.
no subject
Разделитель не всегда запятая. Иногда - точка с запятой. Зависит от настройки системы "разделитель элементов списка".
no subject
Хотя параметр "разделитель" для веб-сервиса отдающего csv, я тоже сделал, на случай "кто-нибудь захочет посмотреть из Excel с русской локалью"
no subject
no subject
no subject
Как только ты сталкиваешься с ситуацией "быстро парсить поток байт" что льётся без остановки, спасают только автоматы (и то лишь в случае регулярных грамматик).
В остальных случаях нужны уже синтаксические анализаторы.
Рукописный лесосипед может требоваться в силу специфичности требований - таких как окружающий шум.
У меня при генерации мультиметодов нужно парсить содержимое комментариев. Но тут прикол в том, что парсеры эгоистичны - они парсят вход целиком.
Пришёл слабать автомат, что извлекает плюсовые комментарии из исходного кода.
Ничего сложного.
Автоматы простые как копейки, и умеют ээфективно парсить регулярные грамматики - в этом их сила.
Хоть, конечно, есть ньюансы применения, и конкретных реализацией автоматов чуть более, чем дохуя.
Но кодировать вручную иногда проще, чем искать хуй-пойми что.
no subject
no subject
Тогда состояния позволяют обрабатывать блок, сразу его пересылать дальше или писать на диск, и лишь затем аккумулировать следующий блок.
Или вообще построить конвейер из параллельного чтения данных по сети, обработке данных (парсингу) и записи блоков на диск.
Так что всё не так просто.
no subject
Я ВЕРЮ!!!!!
Я прошу живой пример из жизни конкретно под CSV, плиз! Я мозгом скриплю - банально не могу представить где такое может произойти. Ну можалуйсто! :)
Про бинарные и т.п. потоковые протоколы - без вопросов.
no subject
И это ещё нормально, у нас вон в csv гигабайтные блобы экспортили из SyBase =)
no subject
no subject
Кстати, это ничем и никем не запрещено - таскать толстые табличные данные в этом формате - универсально, просто, минимум накладных расходов (escaping запятой и перевода строки - мелочи).
no subject
no subject
no subject
и последнее поле в строке по моему, не обработается корректно.
no subject