- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
#include <string>
#include <sstream>
#include <iostream>
int main() {
std::string str;
std::stringstream s("");
std::getline(s, str, '|');
std::cout << "good=" << s.good() <<
" bad=" << s.bad() <<
" fail=" << s.fail() <<
" eof=" << s.eof() << std::endl;
return 0;
}
С древних времен программисты разделились на два лагеря: остроконечников и тупоконечников. Остроконечники всегда заканчивали свои файлы на LF или че там использовалось на их оси (LF - терминатор). А тупоконечники заканчивали файл сразу после последнего символа последней строки, не ставя лишний по их мнению LF (LF - сепаратор). Из-за этого раздора, код ньюфагов то недочитывал пару символов в конце строки, то читал лишнюю пустую, то вообще повторял последнюю строку джважды, чем доставлял им море баттхертов...
Крестостандартизаторы, глядя на этот цирк, решили как-то устранить эту проблему в своей либе. Единственным решением оказалась установка failbit не только при чтении за конец файла, но и при чтении злополучной "пустой" строки...
Жизнь была бы простой и безоблачной, если бы они добавили отдельную функцию gettoken(), в которой этого костыля бы не было...
Например если в потоке у нас "a|b", и мы вызываем std::getline(stream, buf, '|'), то при первом вызове мы получим buf = "a", при втором buf = "b" и установленный eofbit у стрима. Если вызвать его еще раз, то ничего не прочитается, и у стрима включится failbit, и вылетит исключение (если оно разрешено).
Если бы все так и работало, достаточно было бы включить режим исключений у потока, и тупо вызвать по getline'у на каждый токен (и проверить stream.eof(), если хочется убедиться, что стрим дочитался до конца). При нехватке токенов вылетело бы исключение.
Но из-за описанной выше питушни, если в потоке было "a|", при первом вызове мы получим buf = "a", а при втором ничего не прочтется, установятся сразу оба флага - eofbit и failbit и вылетит исключение. Поэтому такой простой подход уже не прокатит, и надо отключать исключения, и втыкать проверки после каждого токена... Что неприятно.
Отсутствие оного.
А альтернативу я нашел: boost::tokenizer или boost::split.
Кто минуснул?!
Это деление только у глупых программистов, которые не знают как делать FSM для lexer'ов/parser'ов.
Причем здесь это? Различия то начинаются еще при записи в файл - тот же vim считает LF терминатором, и добавляет \n к последней строке, а тот же notepad, считает LF сепаратором, и не добавляет. Как FSM для getline'а поможет в борьбе с различиями при записи в файл?
Максимум, чего можно добиться навелосипедив getline - это нормальная работа с обеими форматами. Но ведь он и так это умеет. Зачем изобретать то, что уже прекрасно работает?
А вот gettoken да, можно и написать. Но согласитесь, а не лучше ли было бы, если бы он был готовый, и его не приходилось каждый раз писать заново? В сишке же есть strtok. Он хоть и уёбищен, но есть.
P.S. За что мне поставили минус в комменте про boost::tokenizer я вообще не понял.
Важно не то как оно пишется в файл. Важно то, можно ли оттуда прочитать.
getline() очевидно неправильная функция если тебе нужно читать потенциально битые текстовые файлы и/или файлы с неизвестным заранее разделителем.
"Но ведь он и так это умеет. Зачем изобретать то, что уже прекрасно работает?"
Пример в ГК (и мой личный ограниченый опыт) как бы намекают что оно весьма далеко от "прекрасно."
"В сишке же есть strtok. Он хоть и уёбищен, но есть."
Много лет назад читал от скуки /usr/include/string.h и наткнулся на strpbrk(). Почитал ман, порадовался жизни, и после этого перестал трахатся с strtok(). Рекомендую.
Пример в ГК использует getline не по назначению (из-за того, что авторы не удосужились сделать отдельный gettoken без описанного выше костыля). Отсюда и проблема. А для чтения строк из файла он вполне адекватно себя ведет.
> с неизвестным заранее разделителем
Ну тут да, придется свой парсер-детектор написать.
> strpbrk
Спасибо, не знал про эту функцию ;) Удобно.
Юникс писался армянской диаспорой в Чехословакии...
Снимаю шляпу) Эти слова нужно написать на табличке перед входом на сей сайт.
P.S. http://govnokod.ru/12937 :)
Прочитать float константу в переменную lon
[Прочитать >>]
Пропустить 1 или более пробелов
[Прочитать >>]
Прочитать float константу в переменную lat
Соответственно если сматчилось, то используем, иначе обрабатываем ерор. В [] написано то, в чем я сильно не уверен и скорее всего это (а в этом я уверен) просто связующий\разделяющий символ.
LispGovno
Так и есть.
> сразу понял
Да понять то можно... Ты написать попробуй... Там с действиями в [ ... ] траблы в основном, кресты это ж не ленивый хаскель...
P.S. Хотя траблы с [ ... ] это уже не к спирту, а скорее к фениксу и т.п.
Например? Действия в неожиданном порядке вызываются в соответствии с порядком приоритетов?
Ну и компилится спиртосодержащий код просто пиздец как долго... Не говоря уж о портянках с ошибками, после которых обычные бустовские кажутся несущественными и маленькими.
Кстати, не знаете, есть ли относительно простое (для анскильных питушков) и подробное руководство по Spirit на более-менее русском языке? Желательно, чтобы там охватывалась старая версия (classic) и новая.
А то статьи с примерами обычно пишут в стиле "Давайте напишем Hello, world, теперь распарсим списочек вида a,b,c,d,e;. Смотрите, как всё просто и понятно! Теперь вы знаете Спирит!" Иногда ещё внезапно начинают использовать Phoenix, хотя мозг читателя ещё не отошёл от всей мощи Spirit'а.
Да, документация - это хорошо, но лучше бы почитать в более художественной форме на родном языке.
вы вообще с какой целью интересуетесь? для продакшена спирит в коде - не самый приятный инструмент
Угу. Для серьезных грамматик что-то в духе bison'а и удобнее и быстрее, и ошибки внятные дает... Простенький скриптовый интерпретатор (процедурное подмножество сишки или паскаля) без замашек на производительность на связке bison+flex ваяется за вечер...
А для простых грамматик можно что-нибудь навелосипедить. Выйдет короче и понятней чем спирт. А главное компилиться будет быстро ;)
В основном - для своего развития и повышения компетентности.
Довелось мне писать парсер. Буст использовали не самый новый, новоспирита там ещё не было. Парсер работает, подкрутить грамматику для изменений в будущем я могу, но не чувствую контроля над ситуацией.
Хотелось бы всё осознать и отвязаться если не от периодических заглядываний в документацию, то хотя бы от периодических заглядываний в примеры.
qi::rule<string::const_iterator,int()>
развернутое до POD будет выглядеть так:
http://pastebin.com/YGnTLEtE
мелкую FSM (которая будет правильно обрабатывать отсутствие последнего перевода строки) можно и в десяток строк вместить. даже FSM ее не обязательно называть.
можно чуть больше строк написать и "нагородить" еще и нахождение терминатора строки.
потому что даже с strtok() тебе все равно нужно состояние что бы определить что после последнего разделителя нет больше строки vs. есть пустая строка.
А с getline'ом файл отлично обрабатывается и без FSM (т.к. подобная FSM инкапсулирована в сам getline).
У меня проблема то возникла при парсинге сообщений в духе "111|222|aaa|bbb". Начал писать к парсеру тесты, и напоролся на этот failbit при "111|222|aaa|". Подключил boost::tokenizer (т.к. свой gettoken писать банально и скучно, а разобраться с незнакомым мне куском буста не повредит), и пошел плакаться на ГК ;)
в некоторых случаях я забиваю на эффективность, и делаю аналог перлового/этц split() с помощью string::find_first_of (C++ аналог strpbrk), сигнатура:
догадываюсь что тормозит, но по барабану - потому что мне важнее что работает надежно.
> догадываюсь что тормозит
Если не гигабайтные файлы парсить - не будет :)
> важнее что работает надежно
+1
P.S. Хотя с другой стороны split, возвращающий вектор, может сразу найти какие-то форматные ошибки. А с итератором мы о них узнаем только в ходе разбора.
Задачка тут у нас есть - преобразовать большой xml в много маленьких json. Проблема в том, что используемые xml и json библиотеки работают через коллбэки, вызывая функторы с соответствующими объектами на входе. Обе хотят управление, что в плюсах неудобно.
Мораль: люди, делайте нормальные итераторы, пишите пулл-парсеры, не забирайте управление.
Хотя с DOM'ом оно бы неплохо скрестилось.
> Почему так сделали, я не знаю.
Поди под работу с DOM'ом или подобными иерархиями заточено.
Впрочем, вопрос о максимальном уровне вложенности уже вызывает вопросы. Что ты такое хочешь сделать, извращенец?
Ну проверять незакрытые/лишние скобки то надо.
https://ideone.com/HdzxT8
Мы уже работаем над тем, чтобы пофиксить это в следующей версии.
/fixed
- А вот она!
http://rapidjson.org/md_doc_sax.html
Причём есть даже «PrettyWriter», который на выходе даст отформатированный JSON.
http://rapidjson.org/md_doc_faq.html
твой сплит ничего не возвращает. к нему join() не прикрутишь: join( sep1, split(str, sep2) ); (или еще лучше: join( sep1, apply( split(str, sep2), func1 ) ); )
и в добавок можно всегда результат на экран дампнуть.
в добавок генерализировать токое, по личному опыту, уже давно не пытаюсь. если мелкие тривиальные разницы типа: сплит по строке, сплит по набору символов, мержить соседние сплитеры или нет, сплитить только первые Н подстроки (хвост целеком пихать в последний элемент).
PS я скопипастил сигнатуру именно из того одного места где у меня сплит не имеет аргумент разделитель! он там в пробелы захордкожен (симулирует split /\s+/).
Он третьим аргументом передаст какой-нибудь join_iterator:
но мне все равно писание задом наперед, к чему С++ с итераторами и функтоидами подталкивает, не нравится.
я предпочитаю прямолинейный функциональный код.
собственно говоря, первый split()/join() (а так же keys() и values() для мапов) у меня в С++ появились когда меня просто трахание с итераторами достало в одном пруф-оф-консепт'е. тормозило заметно, но работало.
до этого еще пытался эмулировать слайсы с помощью std::pair<iterator,iterator>, но оно сосало немеряно (в оссобенности когда второй итератор инвалидировался).
Да не, все-таки итераторы это не задом-наперед. Ну а вообще - итераторы удобны только для потоковой обработки. Если надо рандомный доступ - лучше ваши split'ы и join'ы (или их Qt'шные аналоги, если проект на Qt).
Функциональщиной в крестах балуетесь?
continuation passing style же
только же опять задом наперёд...
Forth :)
А что, русского термина нету? Конечный автомат же.
остроконечников, тупоконечников и хуеконечников
лично по граблям не ходил, но наблюдал людей которые пытались обработать ошибки ввода в iostream. как правило их отличает от нормальныю людей тенденция стучатся головой по стенке. в паре мест у нас народ просто забил и переписал на stdio.
к слову, по крайней мере в старой версии гнутой stl, можно было добится что бы все четыре флага были выставлены. последовательности уже не помню, но по сырцам я ее находил. а по сырцам я лазил пытаясь понять накой фиг их там 4ре и чем они отличаются друг от друга.
ЗЫ Согласно вот этому: http://www.cplusplus.com/reference/ios/ios/fail/ - "failbit is generally set by an operation when the error is related to the internal logic of the operation itself;" Другими словами std::getline() призналась что в ней есть ошибка... Вообщем вынос мозгов.
failbit в этом месте вполне логичен для основного применения getline: Но вот для других разделителей он там только мешается.
Ну вернее как. Он вполне логичен как костыль, позволяющий работать с файлами обеих типов одинаково, не обрабатывая лишнюю пустую строку.
То-то я смотрю, как распухают дистрибьютивы линукса (это при том, что ядро весит около ~100 мб), а он как был жопой, так ей и остается. Не зря их логотип напоминает сфинктер с геморроидальными шишками.
~3 мб
> он как был жопой, так ей и остается.
.NET в винде весит каких-то 1.5 ГБ, а она как оставалась жопой так и остается.
Я ведь рассказывал о работе своих прог в винде. Когда .NET 4 прогу я переношу с семерки на хрюшу половина функционала исчезает))
Разрабатывал прогу в платформонезависимом фреймворке, перенес ее на чуть другую платформу с тем же фреймворком и не работает. Это нормально?
P.S. Кстати 4.0 или 4.5, не помню какой точно, на хрюше уже не идет.
Да почему, может быть 4.0 еще идет, а 4.5 - уже нет. Я не помню когда они поломали совместимость, т.к. первый и последний .net, под который я кодил неделю-две имел версию 2.0 :)
Просто я недавно пытался поставить на виртуалку 2013ю визуал студию экспресс, и нужный ей фреймворк не встал на хрю. Пришлось корячить семерку в виртуалбокс...
Виртуалишь?
Жабу, ту и вовсе используя различные ухищрения можно компилить и запускать хоть под 1.4 и ниже, хоть под 1.1.
Байт-код ведь всё тот же. Проблемы только с новыми классами, которые можно собрать и подложить. И новой моделью памяти в 1.5.
+1
многие системные вещи были написаны, переписаны и дописаны
даже есть нюансы между сервис-паками сраной xp, о чем и говорить
или ты хочешь сказать, что апи 15 летней давности должно хватать и поныне?
У Вас, простите, все в порядке?
Коды ошибок иные, во всяком случае на дельфях. Я уже обжегся. Я просто имею в виду, что суть неизменна. Иначе это была бы уже не винда.
кого она еще стоит, главное, чтобы прога на xp/vista/7 шла, и т.п. -
но я не такой человек! Пришлось упорно колдовать. Окончательный вариант: прога определяет версию ОС и в зависимости от
этого включает ту или иную отрисовку.
Кстати, Delphi 7 работает начиная с win98 и кончая семеркой, а вот Delphi 2009 и все последующие - уже нет, так как они юникодные.
Он на делфи 6 вроде написан. И автор обновляться вроде как не собирается. Есть вероятность, что у него винда 9х, и в ней больше ничего не идет...
P.S. А в той же кутишке где-то до 4.3 были и юникод и поддержка 98 винды. :)
P.P.S. А еще в 98й вроде бы нет поддержки больших файлов (4 гига и больше), т.к. еще не было 64 битных перемоток, да и фат один хер такие файлы не понимает.
Гисслер до сих пор сидит на 2-ой или 3-ей Делфи. Я был в шоке, когда узнал. Что это - нежелание раскошеливаться на новый компилятор или попытка сохраненить свой статус "тру-кодера": (форма готовая есть, классы есть, руки есть, голова есть. Что еще надо для кодинга???)
>Есть и приятные моменты. Например, полная поддержка Unicode в TC была написана мной вручную, тогда как в Lazarus все контролы изначально поддерживают Unicode и базируются на UTF-8.
Я являюсь обладателем лицензионных версий всех последних Delphi, поэтому я достаточно хорошо представляю себе их возможности. Но дело тут вот в чем: компиляция exe-файла в Delphi 2 дает на выходе файл, ощутимо меньший по размеру, чем, например, в Delphi 7. Кроме того, тестирование показывает, что exe'шник из-под Delphi 2 работает заметно быстрее, чем его полный аналог, выпущенный компилятором Delphi 7. Я сталкиваюсь с тем, что люди часто удивляются, что Total по-прежнему работает очень быстро. Я собираюсь сохранить эту его особенность, и отчасти секрет тут в правильно выбранном компиляторе.
Добавлю, что, кроме того, Delphi 2 генерирует очень универсальный код, например, с полной поддержкой 16-битовых приложений или Windows 95/98 - у меня до сих пор хватает таких клиентов. В то же самое время TC прекрасно себя чувствует и в Windows 7.
сказал одну очень умную мысль, которая запала мне в душу: не стоит
увлекаться скинами - интерфейс такой программы выглядит вычурно на фоне
остальных окон.
Для плееров конечно же.
Да не, у андроида совместимость годная. Ну настолько, насколько ее вообще можно сделать годной для такого зоопарка устройств и осей.
Тут дело скорее в писателях софта, которые не хотят париться и поддерживать 2.х (меньше стандартных компонентов, нету некоторых апишек, или же нужно подключать compat либу, чтобы они эти апишки юзать и т.п.), и выбирают минимальное сдк повыше...