Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Общие вопросы > Парсер ini файлов |
Автор: Cheloveck 23.6.2009, 21:41 |
Надоело, что виндовые функции семейства *PrivateProfile* каждый раз открывают и читают файл. К тому же функционал очень сомнительный. Написал свою кроссплатформенную версию парсера ini файлов. В инете видел один примерчик, написанный на boost.spirit, но он меня не впечатлил, болше ничего хорошего не находил. Мой парсер использует объектную модель документа (DOM) и способен загружать файл как целиком, так и по частям (равно как и записывать). Это мой первый опыт написания открытого кода, так что необессудте. Сообщайте о любых багах и недочётах в ЛС по e-mail или на jabber, можно и в эту тему. P.S. Тему можно удалить, исходники убрал |
Автор: zim22 23.6.2009, 22:05 | ||
мне в операторе присваивания не понятно несколько моментов: 1) почему возвращается константная ссылка? 2) будет ли ваш код работать правильно, если я отключу assert с помощью #define NDEBUG
|
Автор: zim22 23.6.2009, 22:13 | ||||
повлияет. если логика кода находилась внутри этого макроса. код будет выглядеть так:
|
Автор: Cheloveck 23.6.2009, 22:18 |
zim22, спасибо, поправлю. Да, действительно, что-то такое было у майерса Добавлено через 5 минут и 20 секунд Поправил |
Автор: Lazin 23.6.2009, 22:26 | ||
а зря, если нужно что-то распарсить, то лучше использовать spirit ![]() |
Автор: Cheloveck 23.6.2009, 22:29 |
Lazin, не впечатлил не spirit, а примерчик. |
Автор: nerezus 23.6.2009, 22:36 | ||
|
Автор: azesmcar 23.6.2009, 22:39 | ||
Cheloveck Меня больше всего вот этот момент забеспокоил
return NULL; как это работает. Вызывается конструктор принимающий const char*. Каким образом будете проверять что функция сработала нормально? Ни одного удовлетворяющего стандарту метода я не вижу. Да и вообще, скорее всего еще при возврате значения вылетит. |
Автор: Cheloveck 23.6.2009, 22:42 |
azesmcar, мне представляется, что создастся объект std::string, метод empty() которого вернёт true, но если ты точно знаешь, что будет бяка, то я переделаю на return ""; |
Автор: azesmcar 23.6.2009, 22:44 | ||||
![]() ![]() Я бы использовал исключения, возвращать "" как-то некрасиво. Добавлено через 4 минуты и 5 секунд
|
Автор: Cheloveck 23.6.2009, 22:52 |
azesmcar, я уже протестил. Исправил на return ""; Исключения тут не нужны ИМХО, строка пустая, если не найдена и всё, кажется логично. |
Автор: azesmcar 23.6.2009, 22:55 | ||||
Строка пустая если 1. Невозможно открыть файл 2. файл открыт, но в
ни разу не зашел. А если там в самом деле пустая строка? Исключениями красиво, но не мне решать конечно ![]() |
Автор: Cheloveck 23.6.2009, 22:57 |
azesmcar, хорошо, я подумаю |
Автор: Lazin 24.6.2009, 05:46 | ||
если честно, не понимаю что в этом плохого, лично я использую spirit даже для разбора параметров командной строки, использовать flex/bison ради этого я бы не стал ![]() |
Автор: jonie 24.6.2009, 07:21 |
а где Unicode?! Нафига нам нужны устаревшие однобайтовые кодировки?) |
Автор: Cheloveck 24.6.2009, 15:32 | ||
где ты видел ini файлы в юникоде? в юниксе? так там всё и с char'ом всегда работает. |
Автор: zim22 24.6.2009, 15:52 |
поищите в гугле. они есть. "ini file unicode" |
Автор: nerezus 24.6.2009, 16:32 |
Cheloveck, просто некоторые люди хотят хранить конфиги разнотипные. И, естественно, уникод нужен. jonie, с другой стороны utf-8 позволят обходиться без этого и код такой с ним нормально работает. |
Автор: Cheloveck 24.6.2009, 16:54 |
Была идея использовать std::basic_string вместо std::string и прикрутить шаблоны.... Но я отмёл эту идею как излишнее... юникода не будет!!! Если код действительно заинтересовал, не так уж и сложно изменить его, всё в Ваших руках)) |
Автор: zim22 24.6.2009, 17:43 | ||
это одно и тоже
|
Автор: Cheloveck 24.6.2009, 18:35 | ||
|
Автор: zim22 24.6.2009, 18:47 | ||
Cheloveck, и что? вы хоть бы объяснили, зачем его привели...
![]() |
Автор: Cheloveck 24.6.2009, 18:52 |
Ну, чтоб показать, что basic_string и string не совсем одно и то же. И то, что если в шаблоне передать wchar_t, то получим юникод. |
Автор: zim22 24.6.2009, 18:59 | ||
![]()
под "одним и тоже" я подразумевал, что string является всего-лишь typedef для basic_string<char>. эх, не умеете вы мысли читать... ![]() |
Автор: Cheloveck 24.6.2009, 19:05 |
да, с этим плоховато)) |
Автор: Rififi 24.6.2009, 20:29 |
Cheloveck, где ты видел ini файлы в юникоде? а почему не? var = ∰ఋ୬൬乙㊉ даже если они не в юникоде, но сама программа очень даже может быть в нём и что мне теперь, каждый раз перекодировать всё пришедшее из конфига? да ну нафик такое щастие. |
Автор: Cheloveck 24.6.2009, 20:44 |
Rififi, ничего сложного в перекодировании не вижу, тем блее, что в UNIX системах это будет балластом. Считаю дискуссию по отсутствию юникода не уместной, так как уже ответил, юникода - не будет!!! |
Автор: Cheloveck 24.6.2009, 21:29 | ||||
Содержимое C:\test.ini кодируеи в UTF-8 или в UTF-8 без BOM
Смотрим на месаджбокс и удивляемся, как это мы раньше жили. Из эксперимента видим, что виндовые функции чхали на юникод в файлах. Если файл будет в ANSI - всё работает, из чего следует, что функции каждый раз перекодируют, что пришло из конфига. Просто это скрыто. Написать маленькую функцию-декодер самому очень легко. Не думаю, что это должно быть в парсере. |
Автор: Rififi 24.6.2009, 22:55 |
Cheloveck, ... Смотрим на месаджбокс и удивляемся, как это мы раньше жили. ... а потом читаем насчёт поддержки юникода в Windows и офигиваем от того, что поддерживается только UCS-2, безо всяких там UTF-8 вот оно как, однако. |
Автор: Cheloveck 24.6.2009, 22:59 |
Rififi, иии? от этого работа с UTF-8 файлами не стала другой. |
Автор: Rififi 24.6.2009, 23:30 |
а к чему тогда была написана эта кривизна (я про последний пример)? ты пытаешься засунуть в ucs-2 функцию строку в кодировке utf-8 и радуешься что ничего не получается. |
Автор: Cheloveck 24.6.2009, 23:46 |
Rififi, к тому, что не предполагаются INI файлы в UTF-8. А потдерживать UTF-16/UCS-2 или UTF-32 я не собираюсь вовсе. Пусть сначала Microsoft разбирётся, какую кодировку они хотят использовать. Или же пусть делают как в UNIX, когда есть системная кодировка и все программы корректно с ней работают, используя char. |
Автор: jonie 24.6.2009, 23:50 | ||
а что, ini файлы только в винде бывают? И только в 1 байтовой и ucs-2 кодировке ?)) хреновый дизайн библиотеки - вот ответ.
|
Автор: Cheloveck 25.6.2009, 00:04 | ||||||
файл в UTF-8
О чём ещё говорить, я не знаю. В UNIX'е это работает без проблем. Не устраивает библиотека, не пользуйте. Гоаорить, что хреновая не надо. Она именно такая, как была задумана. Напишите лучше, слава Богу. Да, расскажите... |
Автор: Rififi 25.6.2009, 00:25 |
Cheloveck, ... к тому, что не предполагаются INI файлы в UTF-8 ... при чём здесь таки utf-8 я так и не понял, ну да ладно, не суть. вот что странно - то ты недочётов хотел, то "напишите сами". что касается первого - пожалуйста, получите: отсутствие поддержки юникода под windows в кроссплатформенной библиотеке для меня означает означает жирный минус (а точнее - крест) на этой библиотеке. Пусть сначала Microsoft разбирётся, какую кодировку они хотят использовать что удивительно, они таки разобрались. уже почти 20 лет как (когда там windows 3.0 вышла? ). о как оно получается. |
Автор: UnrealMan 25.6.2009, 00:29 | ||
3) является ли такая реализация exception safe? |
Автор: Cheloveck 25.6.2009, 00:30 |
Rififi, хорошо. Расскажи, что за юникод я должен поддерживать? По моему неведению, я всегда считал UTF-8 юникодом. Покажи как надо читать файлы в "настоящем" юникоде. Добавлено через 3 минуты и 12 секунд В плане? Ссылку я уже убрал. Эксцепшен возникнет только от new, но это должно пользовотельское приложение обработать. Поконкретнее, пожалуйста. |
Автор: Andrew121 25.6.2009, 02:15 |
Cheloveck, Мдя...печально вышло ![]() |
Автор: Lazin 25.6.2009, 06:01 |
UTF-* это не юникод, это кодировки, юникод это стандарт ![]() что-бы использовать твой код в linux, нужно сначала создать локаль ru_RU.cp1251 командой locale-gen |
Автор: Andrew121 25.6.2009, 07:07 |
Да это перебор. При том оч...оч большой! Да и при чем тут юникод?! Вот реально, отпишитесь те, кому жизнено необходим юникод в ини файле. И сам ини файлик приложите. Пожалуйста. И мы, все дружно, подсчитаем. ![]() Ок? Начинаем. |
Автор: jonie 25.6.2009, 07:13 |
Andrew121 самый употребимый язык на планете - китайский (да, да, не английский). вот и думай. Не поддерживать юникод в своих программах - абсолютно неверно и не дальновидно. |
Автор: Andrew121 25.6.2009, 07:19 |
jonie, Ваше замечание принял. А что же с моим предложением? Пожалуйста без намеков и двусмысленности. |
Автор: Andrew121 25.6.2009, 07:38 |
Cheloveck, Дружище, пощитай сколько из них сказали тебе спасибо. И делай выводы............ |
Автор: Lazin 25.6.2009, 08:30 | ||||
отписываюсь, допустим, в ini файле хранится строчка
![]() Добавлено через 2 минуты и 32 секунды даже больше, рассчитывать на то, что путь к файлу будет состоять только символов, чей код <128 (латинские символы, числа итд) - наивно ![]() |
Автор: zim22 25.6.2009, 08:42 | ||
Cheloveck, только не сделайте неправильные ![]() |
Автор: Andrew121 25.6.2009, 08:47 |
Это уже как получится. Кто на что учился... Добавлено через 1 минуту и 3 секунды Lazin, Спасибо что не проигнорировали. 1. |
Автор: Rififi 25.6.2009, 09:27 |
Вы хотите недочётов - их есть у меня! (Ж нет итерации нет поиска по предикату нет поддержки комментариев в конце строки нет соответствия именам функций load-save, read-write нет возможности указывать настройку case-insensetive нет возможности байндинга к переменным в коде пустые строки гонятся через весь цикл комменты не учитываются повторы переменной не поддерживаются multi-threading не поддерживается нельзя делать переменные без секций нельзя раскрывать переменные среды вида: AAA = ${WINDIR}\SYSTEM32\cmd.exe нет типизации - всё гонится в string неправильно парсится строка вида A = (B=C) не исключающие друг-друга проверки в главном цикле парсинга многострочные параметры не поддерживаются load-save одного и того же файла уничтожает все комментарии пустые секции также уничтожаются допускаются левые имена как в переменных, так и в секциях если записывать пустые данные в существующий файл, то функция write уничтожает его использование iterator вместо const_iterator потом уже просто надоело их находить ![]() |
Автор: Andrew121 25.6.2009, 09:43 | ||
Поясните пожалуйста. Поясните. А разве в стандартном ини такое поддерживается?
Вы полагаете, что этим должны заниматься функции манипуляции ини файлом? Имеете в виду что-то типа variant? Опять же - А разве в стандартном ини такое поддерживается? С остальным согласен. 2. |
Автор: Lazin 25.6.2009, 10:01 |
а зачем он там? в несколько потоков парсить ini файл? ![]() |
Автор: Andrew121 25.6.2009, 10:15 |
Я не представляю реального примера. Но теоретически...возможно. |
Автор: UnrealMan 25.6.2009, 13:43 | ||
И в каком же состоянии будет пребывать объект? Что будет при вызове его деструктора? А зачем? Как отличать комментарии от данных, не являющихся комментариями? Для этого можно использовать синхронизирующий прокси. |
Автор: Cheloveck 25.6.2009, 14:51 | ||||||||||||||||||||||||||||||||||||||||||||||
По пунктам
это зачем?
Всегда считал, что все ключи заранее известны. Поиск по предикату явно лишний.
а где она есть? Единого стандарта на INI файлы нет. Я читал, что комменты в конце строки потдеживают только некотроые программы.
Хорошо, просмотрю код и поправлю.
ниразу не предполагалась. Это замедлит работу, а нужно ли? Мне нет, код писался в первую очередь для себя.
предполагается работа только с копиями объектов, никакого доступа к оригиналу. Хочешь изменить - обнови. Это достаточно распространённый подход, я не знаю, почему он вызвал недоумение. Наверное, потому что хочется просто придраться.
Пустые строки гонятся, если находятся между комментами. Ибо я стараюсь сохранить комменты между секциями в первозданном виде.
где не учитываются? если с файлом целиком работать? да, не учитываются. Не представляю, как можно хранить ещё и комменты, да и зачем?
Я должен вернуть две строки? Брось, это уже перебор. Никто не потдерживает повторы.
А зачем?
Можно. loadGlobalSection, но только, если секций в файле нет. Смешанных типов никогда не видел. Либо есть секции, либо их нет вообще.
Угу, а ещё не выполняет команды оболочки и не перезагружает компьютер, если он завис...
Так везде. Ну, допустим в VCL встроен конвертор. А надо оно? Руки на что? Эта фанкция тут так же не нужна. Данные хранятся в строках и дожны быть в них представлены.
Такие строки хранить запрещено, не знаю как у всех, но у меня нельзя.
Что должно чего исключать? Если найдена секция, то проверка на запись проходить не будет, а если коммент - то ни запись, ни секция парситься не будет.
Формат хранения несеольких строк должен определятся пользовотелем. К этому выводу я пришёл, когда задавался вопросом хранения многострочных значений
Кажется я об этом уже сказал.
Если ты захочешь что-то написать в эту секцию, она появится. Зачем нужны пустые секции? Ну, ладно здесь я ещё более или менее согласен.
Левые? это какие? В секциях любые символы кроме [, = и ]. А чем плохое имя секции &%*/--, если ты об этом?
А это не логично? Загрузи файл и допиши свои пустые данные? Вообще, бред какой-то...
Ну, если не заметил, то функции это вспомогательные и объявлены в cpp файле. И я меняю значение переменной обращаясь к итератору.
Если юзер обработает bad_alloc, то всё будет отлично, если не обработает, то программа повиснет на любом из этих исключений. Добавлено @ 15:00
Я сделал выводы. Боюсь, что Вы их посчитаете неправильными, но я больше никогда не буду выкладывать код. Даже если он будет идеальным, всё-равно его обосрут с ног до головы. Потому что у халатика нет преламутровых пуговец. ЗЫ Тема закрыта, линки убрал. Обсуждать больше нечего. |
Автор: Andrew121 25.6.2009, 16:43 | ||
Что и требовалось доказать. |
Автор: zim22 25.6.2009, 17:32 |
это же здорово, когда код обсирают! гораздо хуже, когда его хвалят. вы просто "фишку не рубите" ![]() *** ревью кода |
Автор: UnrealMan 25.6.2009, 18:40 |
Ну, если не считать того, что программа через некоторое время, скорее всего, издохнет на фиг из-за двойного удаления, всё будет просто превосходно ![]() |
Автор: jonie 25.6.2009, 19:52 |
на мой взгляд стоит делать такую библиотеку так: Для начала реализовать SAIni (simple api for ini) парсер, путь даже на С чистом. Сам файл зачитывать нет нужды в память - достаточно описывать элементы как <смещение, длина>. Работать с файлом как проекцией на память (хотя это и не обязательно). Также парсер для записи потоковой нужен. Вопросы кодировки решаются тут. Далее над этим парсером надстраивается DOM парсер. В простейшем случае это вектор базовых IElement. В нем достаточно одного метода - ELEMENT_TYPE GetType(). Например Section наследуется от IElement и дополнительно содержит vector элементов типа "ПолеСЗначением". Ну и также присуствуют типы : Поле, Значение, Комментарий. Значение абстрактное, и может быть ЗначениеТипаInt, ЗначениеТипаFloat, ЗначениеТипаСтрока etc. При чтении используется "ЗначетиеТипаСтрока". Тут есть где развернуться шаблонолюбителям 8) Собственно все. Думаю проблем с потерей комментариев например не должно быть...конечно, гемморой с вставкой в середину, ну я думаю это не такая большая проблема на самом деле, и она решаема. Как вам идея ? /* если ктото не чостет это бредом, то можно поучавствовать в создании - одному лень и скучно */ |
Автор: Rififi 25.6.2009, 22:39 |
UnrealMan, нет поиска по предикату А зачем? stl-way (: Как отличать комментарии от данных, не являющихся комментариями? очень просто: если символ комментария находится внутри строкового литерала - то он считается частью данных. иначе - комментарий. |
Автор: UnrealMan 26.6.2009, 12:29 | ||
Ini-файл - это по сути хранилище ассоциативного массива ассоциативных массивов. По названию секции находим секцию, по названию ключа находим значение. Покажи, где std::map реализует поиск по предикату.
Ах, тут ещё строковые литералы надо вводить. А вслед за этим escape sequences, universal character names и директивы препроцессора C? ![]() |
Автор: jonie 26.6.2009, 18:05 |
ini файл хорош тем, в отличие, например от xml что не требует специальных знаний вроде перечня символов подлежащих экранированию, DTD схем, XSD схем и т.д. |