LINUX.ORG.RU

C++, хочу парсер простого текстового формата написать.


0

0

Есть структура:

struct Item
{
    std::string str_utf_8;
    unsigned long len;
    unsigned long position;
    bool flag;
};

Есть их список. Надо человеко-френдли сохранить в файл.

Хотел в json сохранять - заюзал boost::property_tree::write_json(). Оказалось, что json сохраняет символы выше 127 специальной конструкцией \uXXXX. Логично, но хотелось, чтобы юзер без спецсредств UTF-8 строки глазами читал в таком файле. Вдобавок оказалось, что read_json() обратно эту хрень ещё и читать не умеет - советуют jsoncpp-0.5.0 юзать.

Ну его нах!

Захотелось написать записыватель-считыватель примитивного формата, типа:

<длина utf-8 мяса в байтах> <байты строки> <ничего не значащие пробелы и декоративные переводы строки> <параметр1> <параметр2>

Выглядеть это будет так примерно:

81 текстовая строка с пробелами на 81 байт 99 88 T
81 текстовая строка с пробелами на 81 байт 99 88 T
81 текстовая строка с пробелами на 81 байт 99 88 T
81 текстовая строка с пробелами на 81 байт 99 88 T

Кто чё скажет? Может я гоню? Может есть более правильный путь?

Кстати, вспомнил про sqlite-БД. Скайп в ней свои логи хранит от чатов и всякие настройки вроде. Но через текстовый редактор неудобно зырить на это мясо.

bool flag;

Забавно. А для чего оно?

f1xmAn ★★★★★ ()
Ответ на: комментарий от anonymous

Не, у меня utf-8 строка - это любой набор байт, кроме нуля. Ну, то есть там могут быть запятые и переводы строки, что порвёт CSV.

kiverattes ★☆ ()

ну и запиши в цикле через потоки, делов то

x0r ★★★★★ ()
Ответ на: комментарий от kiverattes

Тогда человеко-френдли вряд ли толком получится. Чисто на правах идеи следующий формат:

<magic-string> <len> <pos> <flag>\n
random\r\n
    stream\n
\t       of\0
            bytes
<magic-string> <len> <pos> <flag>\n
more
   random
 stuff

Можно к заголовку записи добавить crc. A lá:

<magic-string> <len> <pos> <flag> <crc>\n
<data>
PS: А C++ — это обязательное условие? Вот я тут в последнюю неделю занялся Go и мне эта штука нравиться всё больше и больше…

beastie ★★★★★ ()
Последнее исправление: beastie (всего исправлений: 1)
Ответ на: комментарий от kiverattes

я может чего-то не понимаю конечно, но libreoffice успешно справляется с переносами. в стандарте (rfc4180) написана примерно такая вещь:

escaped = DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTE
COMMA = %x2C
CR = %x0D ;as per section 6.1 of RFC 2234 [2]
DQUOTE = %x22 ;as per section 6.1 of RFC 2234 [2]
LF = %x0A ;as per section 6.1 of RFC 2234 [2]
CRLF = CR LF ;as per section 6.1 of RFC 2234 [2]
TEXTDATA = %x20-21 / %x23-2B / %x2D-7E

в переводе означает, что между кавычками (DQUOTE) могут находится переносы строк (CR и LF), даже кавычка может быть, правда заменяется на (2DQUOTE), единственный минус в этом всем - ограничение на символы в TEXTDATA. это да, проблема.

anonymous ()
Ответ на: комментарий от anonymous

но этот же libreoffice при попытке сохранить в utf благополучно соглашается и нарушает стандарт, примерно так:

00000000 22 D0 BF D1 │ 80 D0 B8 D0 │ B2 D0 B5 D1 │ 82 0A D0 9C  "п р и в е т .М
00000010 D0 B8 D1 80 │ 22 2C D0 B9 │ D1 86 D1 83 │ 2C 61 73 64  и р ",й ц у ,asd
00000020 0A                                                     .
что дает тебе полное право поступить аналогично, плюсом будет возможность редактирования простому пользователю через стандартные табличные процессоры.

anonymous ()
Ответ на: комментарий от beastie

Я не понял как вы будете парсить ваш random stuff.

Пока я вижу такой формат

71 собака собака собака 81781 92831 true <random stuff until \n>
71 собака собака собака 81781 92831 true <random stuff until \n>
71 собака собака собака 81781 92831 true <random stuff until \n>
71 собака собака собака 81781 92831 true <random stuff until \n>

Здесь меньше свободы, но:
* не зависит от endianness машины
* random stuff until \n позволяет быть готовым к расширению формата

Это проект на C++ с 1.5-летней историей, плюс обработка звука - хочется максимальной производительности.

kiverattes ★☆ ()
Ответ на: комментарий от kiverattes

Никак парсить не буду, а буду ждать появления \n<magic-string>. Ну и длина известна.

beastie ★★★★★ ()
Последнее исправление: beastie (всего исправлений: 1)
Ответ на: комментарий от beastie

А, ждать magic-string. Не просёк фишку. Но рисковано - в random bytes может случайно появиться magic. Голосуйте за мой формат! )

kiverattes ★☆ ()
Ответ на: комментарий от kiverattes

может случайно появиться magic

Да, это одна из возможных проблем. Именно по этому я предложил CRC на заголовок.

beastie ★★★★★ ()
Ответ на: комментарий от kiverattes

В твоём формате проблема в

… <random stuff until \n>

Ты сам сказал, что в «random stuff» могут быть переводы сторки. Хотя… зная длину… возможно и сработает. Просто по «magic-string» ориентироваться проще. А так, те же яйца, вид в профиль.

И, кстати, что мешает просто запилить кошерный генератор json с utf и всем подобным?

beastie ★★★★★ ()
Последнее исправление: beastie (всего исправлений: 3)

ASN.1, Google Protobuf, Apache Thrift, сотни их... что, ни один не подходит?

rand ()
Ответ на: комментарий от beastie

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

anonymous ()
Ответ на: комментарий от beastie

А, у меня особый random - там нет переводов строки ) Мой рандом рассчитан на появление последовательностей типа «3938 19283 91» из нового формата. Хотя кто мешает появиться там ещё одной UTF-8 строке, конечно... Стрелять-колотить! Тогда я не прав.

Кошерный генератор json есть - jsoncpp-0.5.0, но он строки с символами выше 127 сохраняет в виде \uXXXX\uXXXX\uXXXX - на такое смотреть не клёво.

kiverattes ★☆ ()
Последнее исправление: kiverattes (всего исправлений: 2)
Ответ на: комментарий от anonymous

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

Т.е. имеем примерно следующее:

<num entries>
<off 32 byte> <len 32 byte>
<off 32 byte> <len 32 byte>
…
<off 32 byte> <len 32 byte>
<blob>
EOF

Но это больше для бинарного формата подходит.

beastie ★★★★★ ()
Последнее исправление: beastie (всего исправлений: 4)
Ответ на: комментарий от kiverattes

но он строки с символами выше 127 сохраняет в виде \uXXXX\uXXXX\uXXXX - на такое смотреть не клёво.

Зато портабельно. Кто тебе гарантирует big или little-endian систему, где это читаться будет?

beastie ★★★★★ ()
Ответ на: комментарий от beastie

Я пару раз изобретал такой формат:

uint8_t - версия файла
uint64_t - размер страницы. Страница содержит кучу структур до упора. Каждая стурктура - кусок байт, которому предшествует размер этого куска.
   uint64_t - размер мяса
   char[] бинарное мясо в платформо-зависимом виде
   uint64_t - размер мяса
   char[] бинарное мясо в платформо-зависимом виде
   uint64_t - размер мяса
   char[] бинарное мясо в платформо-зависимом виде
   ...
uint64_t - размер следующей страницы или EOF

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

kiverattes ★☆ ()
Ответ на: комментарий от beastie

Никто не гарантирует и это я тоже хотел бы учитывать, поэтому не могу сделать бинарный формат, сохраняя содержимое кусков памяти типа uint64_t. Но вот то, что в байте 8 бит мне может гарантировать практически любая современная система, поэтому поведение «открыл блокнотом - увидел буковки» обеспечить можно.

Хотя незнаю, нафига мне такое. В техническом задании такого нет - чтобы блокнотом открывать и любоваться.

kiverattes ★☆ ()
Ответ на: комментарий от kiverattes

И кстати, если таки вернёшься к бинарному формату, напомню о network-byte-order — в нём можно относительно безболезненно хранить, если учитывать при чтении и записи на любой-endian-системе. Но ASCII конечно лучше.

Одним словом или network-byte-order и бинарный формат или \uXXXX и ASCII (0—127). Выбирай. Но я бы всё таки взял готовое решение и не искал бы приключений на свою пятую точку.

beastie ★★★★★ ()
Последнее исправление: beastie (всего исправлений: 2)
Ответ на: комментарий от beastie

Я щас придумал ещё один крутой формат

N71N898D77собака собакаN99

Расшифровка:

number 71
number 898
data len 77 = "собака собака"
number 99
:)

Почти как ASN.1

kiverattes ★☆ ()

Есть их список. Надо человеко-френдли сохранить в файл.

item_name{
  len = 123;
  pos =  20,30;
  flag true;
};

надеюсь идею ты понял.

Кстати, вспомнил про sqlite-БД. Скайп в ней свои логи хранит от чатов и всякие настройки вроде. Но через текстовый редактор неудобно зырить на это мясо.

по слухам умеет libreoffice.

drBatty ★★ ()
Ответ на: комментарий от beastie

Ладно, не будем злобствовать на ночь глядя. Скомпилил я jsoncpp-0.5.0, работает вроде. Щас ещё проверю как оно файл обратно читает.

У меня пока один вопрос - как оно 150-мегабайтный json сожрёт... Надо будет потестить.

kiverattes ★☆ ()
Ответ на: комментарий от kiverattes

jsoncpp-0.5.0 рулит чуть более, чем полностью!

Оно даже UTF-8 строки сохраняет без \uXXXX вот так:

{
   "marks" : [
      {
         "len" : 1.0,
         "pos" : 440832.0,
         "text" : "тыщ!"
      },
      {
         "len" : 1.0,
         "pos" : 1170688.0,
         "text" : "текст с мать их кавычками\"\"\"!!!1111"
      }
   ],
   "params" : {
      "framerate" : 44100
   }
}
Можно даже комменты из файла прочитать и сохранить. Умеет читать-писать в std::ostream, сохраняется надежда чтения гигабайт. Синтаксис проще, чем boost::property_tree - там пока дерево заполнишь, борода порвётся.

Правда, пришлось double юзать, ибо там нет long, а только int, а мне надо номер семпла в много-гиговых WAV-файлах сохранять.

kiverattes ★☆ ()
Последнее исправление: kiverattes (всего исправлений: 2)
Ответ на: комментарий от kiverattes

Замечательно, что json взлетел, но на будущее не жуй мозг длинами строки, а используй экранирование. Для коротких строк — экранируй \n (\r\n), признак конца — собственно \n. Для длинных, в пользу удобочитаемости и изменяемости, используй почтовый формат: признак конца — «\n.\n», кодирование — s/^(\.+)$/.\1/, декодирование — s/^\.(\.+)$/\1/.

arturpub ★★ ()

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

pathfinder ★★★ ()

может проще писать/читать в бинарном формате а для просмотра написать свой вьювер?

quest ★★★★ ()
Ответ на: комментарий от kiverattes

у меня utf-8 строка - это любой набор байт, кроме нуля

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

no-such-file ★★★★★ ()
Ответ на: комментарий от no-such-file

Смотреть - vim, gedit... Не понял в чём трудность. Редактировать этот мой формат - хреново: захотел добавить 2 кириллических символа - и нужно ещё прибавить число 4 к числу байтов. Бороду сломать можно.

Но, в общем-то проблема решена, так как jsoncpp взлетел без хитрого кодирования байтов выше 127. Мне такой вариант с экранированными символами и голым utf-8 в кавычках очень нравится. Домохозяйка может открыть блокнотом и добавить данные.

kiverattes ★☆ ()
Ответ на: комментарий от kiverattes

Редактировать этот мой формат

Так вам еще и редактировать? Тогда не страдайте фигней - сохраняйте в бинарном виде и сделайте свою смотрелку/редактор с валидацией. А то ведь домохозяйка порушит JSON легко, а найти косяк в большом файле - бороду сломать можно.

no-such-file ★★★★★ ()

это не юзерфрендли, т.к. юзер не сможет редактировать (или отредактирует и всё отвалится).

Правильно посоветовали csv. Тебе только нужно будет все \n \r и твои разделители (допустим \t) поэскейпить. Будет более менее.

invy ★★★★★ ()
Ответ на: комментарий от invy

Что «это»?

Народ, вы чё внатуре? Json ведь взлетел, чё вам ещё надо?

kiverattes ★☆ ()
Ответ на: комментарий от kiverattes

формат твой, описанный в первом сообщении.

Народ, вы чё внатуре? Json ведь взлетел, чё вам ещё надо?

это называется: «тему не читай, сразу отвечай» :)

invy ★★★★★ ()
Ответ на: комментарий от kiverattes

Json ведь взлетел, чё вам ещё надо?

ТС хочет свой написать, с блекджеком и шлюхами. И правильно делает, ибо опыт бесценен.

drBatty ★★ ()
Ответ на: комментарий от invy

А CSV может содержать UTF-8 строки и понимает он экранирование кавычек и переводов строки?

kiverattes ★☆ ()

XML придуман именно для этого - можно сохранить всё и это можно потом посмотреть глазами и отредактировать в любом нормальном редакторе, редактор даже синтаксис подсветит и валидность проверит.

vtVitus ★★★★★ ()
Ответ на: комментарий от vtVitus

XML ущербен тем, что там нет списков встроенных. Там надо вещи явно нумеровать, присваивая им атрибут типа «id». Плюс эти долбанные тонны скобочек. JSON, короче, победил давно на планете )

kiverattes ★☆ ()

Оказалось, что json сохраняет символы выше 127 специальной конструкцией \uXXXX

Какие-то у тебя неправильные пчелы. Сишная библиотека сохраняет правильно.

Anon ()
Ответ на: комментарий от vtVitus

и это можно потом посмотреть глазами

и сломать глаза и пожелать развидеть увиденное!

http://www.boost.org/doc/libs/1_54_0/libs/serialization/example/demo_save.xml

Удачи с редактированием! :D

XML ущербен. Некоторые скажут, что он только для роботов. Но и тут у меня есть аргумент: у xml огромный оверхед по сравнению с тем же json'ом.

invy ★★★★★ ()
Последнее исправление: invy (всего исправлений: 1)
Ответ на: комментарий от kiverattes

ещё раз повторюсь:

понимает он экранирование кавычек и переводов строки

да, описано в стандарте (не экранирование, а прямое использование, удваиваются только кавычки)

http://www.linux.org.ru/forum/development/9467559?cid=9467669 (комментарий)

UTF-8 строки

да, libreoffice этим пользуется, правда это не соотсветствует стандарту rfc4180

http://www.linux.org.ru/forum/development/9467559?cid=9467684 (комментарий)

anonymous ()
Ответ на: комментарий от invy

Удачи с редактированием!

Открыл в редакторе. Даже не знаю что это, но координаты, названия и т.п. изменить запросто.

XML ущербен

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

А про json, как мы видим товарищ (тоже как я понимаю фанатик) ищет ответ на форуме пол дня, на любой библиотеке xml всё решается за 30 минут.

vtVitus ★★★★★ ()
Ответ на: комментарий от kiverattes

А чё за вопросы? Где?

Укурился? ты топикстартер.

vtVitus ★★★★★ ()
Ответ на: комментарий от kiverattes

<ul> <li>1</li> <li>2</li> <li>3</li> </ul>

Это по твоему не список?

bjorn ()
Ответ на: комментарий от vtVitus

про xml можно сказать все, кроме того, что его удобно читать. Как ты его не подсвечивай, а приличных размеров xml воспринимать невозможно. Да и не нужно.

cdshines ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.