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-БД. Скайп в ней свои логи хранит от чатов и всякие настройки вроде. Но через текстовый редактор неудобно зырить на это мясо.

★☆

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

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

… <random stuff until \n>

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

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

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 3)
Ответ на: комментарий от 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 ★☆
() автор топика
Ответ на: комментарий от 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 ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.