Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Апрель 21, 2014, 19:55



Название: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 21, 2014, 19:55
Добрый день

Оригинал здесь http://www.prog.org.ru/topic_26887_0.html (http://www.prog.org.ru/topic_26887_0.html). Для удобства содержательная часть (как я ее понял) ниже

Мне нужно распарсить некоторый текст, формат которого предполагает наличие комментариев. Комментарий начинается с определённого символа и заканчивается другим.
 ..
Вот маленький пример: символ начала коммента - %, конец коммента - \n):
Код
C++ (Qt)
#include <iostream>
#include <boost/regex.hpp>
#include <string>
#include <list>
#include <boost/range/istream_range.hpp>
#include <algorithm>
 
template <class T = char>
class tex_string_iterator : public std::iterator<std::bidirectional_iterator_tag, T, ptrdiff_t, const T*, const T&>
{
public:
   typedef T char_type;
   typedef std::basic_string<T> string_type;
   typedef typename std::basic_string<T>::const_iterator string_iterator;
 
   tex_string_iterator(string_iterator begin, string_iterator end, T bra = '%', T ket = '\n')
       : _begin(begin), _end(end), _it(begin), _bra(bra), _ket(ket)
   {
       make_comments_list();
   }
 
   tex_string_iterator(const tex_string_iterator<T>& iter)
       : _begin(iter._begin), _end(iter._end), _it(iter._it),
         _bra(iter._bra), _ket(iter._ket), _comments_list(iter._comments_list) {}
 
   tex_string_iterator<T>& operator=(const tex_string_iterator & iter) {
       if (this != &iter) {
           _begin = iter._begin;
           _end = iter._end;
           _it = iter._it;
           _bra = iter._bra;
           _ket = iter._ket;
           _comments_list = iter._comments_list;
       }
       return *this;
   }
 
   tex_string_iterator() {}
 
   ~tex_string_iterator() {}
 
   const T& operator*() const { return *_it; }
 
   const T* operator->() const { return _it; }
 
   tex_string_iterator<T>& operator++() {
 
       if (*_it != _bra) {
           if (++_it == _end)
               return *this;
           if (*_it != _bra)
               return *this;
       }
 
       for (const auto & comment : _comments_list) {
           if (comment.begin() == _it) {
               _it = comment.end();
               if (_it == _end)
                   break;
 
               if (*(++_it) != _bra)
                   break;
           }
       }
 
       return *this;
   }
 
   tex_string_iterator<T> operator++(int) {
       tex_string_iterator<T> tmp = *this;
       ++*this;
       return tmp;
   }
 
   tex_string_iterator<T>& operator--() {
 
       if (*_it != _ket) {
           --_it;
           if (*_it != _ket)
               return *this;
       }
 
       for (const auto & comment :_comments_list) {
           if (comment.end() == _it) {
               _it = comment.begin();
               if (_it == _begin)
                   break;
 
               if (*(--_it) != _ket)
                   break;
           }
       }
 
       return *this;
   }
 
   tex_string_iterator<T> operator--(int) {
       tex_string_iterator<T> tmp = *this;
       --*this;
       return tmp;
   }
 
   template <class R>
   friend bool operator==(const tex_string_iterator<R> &, const tex_string_iterator<R> &);
 
   template <class R>
   friend bool operator!=(const tex_string_iterator<R> &, const tex_string_iterator<R> &);
 
private:
   string_iterator _begin;
   string_iterator _end;
   string_iterator _it;    //current iterator
   T _bra;                 //open comment symbol
   T _ket;                 //closed comment symbol
   std::list<boost::iterator_range<string_iterator>> _comments_list;
 
   void make_comments_list() {
       if (_begin == _end)
           return;
 
       auto first = _begin;
       auto second = _begin;
 
       while ((first = std::find(first, _end, _bra)) != _end) {
           second =  std::find(first, _end, _ket);
           _comments_list.push_back(boost::iterator_range<string_iterator>(first, second));
           first = second;
       }
   }
};
 
template<class T>
inline bool operator==(const tex_string_iterator<T> & x, const tex_string_iterator<T> & y) {
   return (x._it == y._it);
}
 
template<class T>
inline bool operator!=(const tex_string_iterator<T> & x, const tex_string_iterator<T> & y) {
   return !(x == y);
}
 
int main()
{
 
   std::string buffer = "text text %comment comment\n text nocomment";
 
   tex_string_iterator<char> ibegin(buffer.begin(), buffer.end(), '%', '\n');
   tex_string_iterator<char> iend(buffer.end(), buffer.end());
 
   boost::regex_iterator<tex_string_iterator<char>> it(ibegin, iend, boost::regex("(com)"));
   boost::regex_iterator<tex_string_iterator<char>> end;
   for (; it != end; ++it) {
       std::cout << it->str(1) << std::endl;
   }
 
  return 0;
}
 



Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 21, 2014, 19:59
Хорошее голосование.  ;D
Хотите ли вы разбираться в C++?
На форуме домохозяек вы бы произвели фурор таким голосованием.

Хотите избавится от комплекса неосилятора? Не поможет. ;)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 21, 2014, 20:12
Хорошее голосование.  ;D
Хотите ли вы разбираться в C++?
На форуме домохозяек вы бы произвели фурор таким голосованием.

Хотите избавится от комплекса неосилятора? Не поможет. ;)
Ох и злобный дустовец попался  :) Мое мнение "3", я считаю что владение задрочеными обобщенными конструкциями имеет к знанию языка очень косвенное отношение. Все-таки С/С++ никогда не обладал гибкостью интерпретатора (что нормально, недостатки = продолжение достоинств). И попытки насилия над языком есть извращение (не спорю - интересное  :))


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 21, 2014, 20:20
я считаю что владение задрочеными обобщенными конструкциями имеет к знанию языка очень косвенное отношение. Все-таки С/С++ никогда не обладал гибкостью интерпретатора
Как по вашему обобщенные конструкции соотносятся с интерпретаторами?  ::)
Никакого "насилия над языком" нет, это ваши фантазии. Все что вам не удалось осилить из языка, вы считаете задроченым и не нужным.
К нашей радости вы хотя бы контейнеры осилили и QString, а то бы сейчас нам рассказывали как они ненужны.  ;D


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: OKTA от Апрель 22, 2014, 00:01
Не, ну правда, код дичайший - ногу сломаешь  ;D
Может он и выглядит умно, но то, что ногу сломаешь - это точно  ;D

Я еще далеко не профессионал, но знаю, что профессиональный код пишется "для дебилов". Не раз заглядывал в код, который пишется для архи-сложных систем и там все просто, как два байта переслать  ;D А тут застрелиться желание возникает, нежели разобраться, как и что работает)))))


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 22, 2014, 00:18
Не, ну правда, код дичайший - ногу сломаешь  ;D
Может он и выглядит умно, но то, что ногу сломаешь - это точно  ;D

Я еще далеко не профессионал, но знаю, что профессиональный код пишется "для дебилов". Не раз заглядывал в код, который пишется для архи-сложных систем и там все просто, как два байта переслать  ;D А тут застрелиться желание возникает, нежели разобраться, как и что работает)))))

Хотите способ, как лишить девственности Ваши наивные представления о профессиональном коде и решениях?   
Полистайте перед сном  исходники boost'а, особенно boost::spirit
Возможно, после этого ваше мнение измениться..  :)

А вообще, дело даже не в конкретной реализации.. Вам не нужно знать что скрыто под капотом.. Важно архитектурные решения, сами подходы к решению проблем.. Гибкость и расширяемость.
Вот igors не разобравшись с проблемой, полез в копания каких то не существенных деталей.. частностей..  А Вы ведётесь на это(   


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: kamre от Апрель 22, 2014, 01:03
владение задрочеными обобщенными конструкциями имеет к знанию языка очень косвенное отношение
А какие именно конструкции в приведенном выше примере "задроченные/обобщенные"?

Вроде код читается относительно не сложно. Но по нескольким моментам возникают вопросы:
  • зачем переопределять конструкор копии и оператор присваивания, чем сгенерированные по умолчанию не подходят?
  • зачем жестко привязываться к std::basic_string, вроде бы такая обертка возможна для любого bidirectional итератора?
  • почему бы не отслеживать текущий элемент в _comments_list и не делать линейный поиск в ++/-- ?
  • почему в == не сравниваются begin/end?


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 22, 2014, 07:54
владение задрочеными обобщенными конструкциями имеет к знанию языка очень косвенное отношение
А какие именно конструкции в приведенном выше примере "задроченные/обобщенные"?

Вроде код читается относительно не сложно. Но по нескольким моментам возникают вопросы:
  • зачем переопределять конструкор копии и оператор присваивания, чем сгенерированные по умолчанию не подходят?
  • зачем жестко привязываться к std::basic_string, вроде бы такая обертка возможна для любого bidirectional итератора?
  • почему бы не отслеживать текущий элемент в _comments_list и не делать линейный поиск в ++/-- ?
  • почему в == не сравниваются begin/end?

Согласен, необходимости в коп.конструкторе и операторе присваивания сейчас нет)

Да, к std::basic_string тоже не обязательно привязываться (не хотел пугать igors'са ещё одним шаблоном  :) )

3) Таки да, вчера как раз это исправил (но можно сделать ещё эффективнее)

4) begin и end не сравниваются из-за тог, что тогда такое условие не выполнится:
Код
C++ (Qt)
   tex_string_iterator<char> iter(buffer.begin(), buffer.end(), expr);
   tex_string_iterator<char> end(buffer.end(), buffer.end(), expr);
 
   for (; iter != end; ++iter) { // У iter и у end не совпадают диапазоны
       std::cout << *iter;
   }
 
 
Это можно решить, например, если передавать в конструктор три итератора: начало и конец последовательности и + ещё текущий итератор..
или ссылку на строку + итератор..   
 


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: OKTA от Апрель 22, 2014, 08:26
Не, ну правда, код дичайший - ногу сломаешь  ;D
Может он и выглядит умно, но то, что ногу сломаешь - это точно  ;D

Я еще далеко не профессионал, но знаю, что профессиональный код пишется "для дебилов". Не раз заглядывал в код, который пишется для архи-сложных систем и там все просто, как два байта переслать  ;D А тут застрелиться желание возникает, нежели разобраться, как и что работает)))))

Хотите способ, как лишить девственности Ваши наивные представления о профессиональном коде и решениях?   
Полистайте перед сном  исходники boost'а, особенно boost::spirit
Возможно, после этого ваше мнение измениться..  :)

А вообще, дело даже не в конкретной реализации.. Вам не нужно знать что скрыто под капотом.. Важно архитектурные решения, сами подходы к решению проблем.. Гибкость и расширяемость.
Вот igors не разобравшись с проблемой, полез в копания каких то не существенных деталей.. частностей..  А Вы ведётесь на это(   

Хорошо, почитаю  :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 22, 2014, 13:00
Хотите способ, как лишить девственности Ваши наивные представления о профессиональном коде и решениях?   
Полистайте перед сном  исходники boost'а, особенно boost::spirit
Возможно, после этого ваше мнение измениться..  :)
Заметьте как резко возросла Ваша самооценка :) Вы уже знаете как пишут профессиональный код, смело считаете представления других наивными и.т.п.

А ведь это всего лишь один из возможных подходов. Полистайте напр исходники Bullet, а можно и просто Qt, и... о боже - никакого буста нет! Да и std если и найдется, то жалкие крохи. Как и во многих др уважаемых мною исходниках - и это не мешает им иметь большой успех.

Что мне не нравится в Вашем коде - что он требует неоправданных усилий для его понимания. Из первого десятка строк я ничего не извлекаю, то есть я понимаю сынтаксыс но не ф-ционал. Нужно смотреть дальше, только минут через 20 что-то проясняется - и то не вполне. Нет содержательных имен методов/вызовов за которые хотелось бы зацепиться, все свалено в операторы/итераторы. Как использовать этот код повторно? По-моему никак, он заточен на одну конкретную задачу.

Обычным оправданием приводится "общность", т.е. это работает и для std::string и для QString и еще для бог весть чего. Но тогда чего у Вас юзается char (ведь уникод гораздо больше в масть). И не слишком ли высока цена пресловутой "общности"? Чем не устраивал QString? Наверное хотелось "профессионально" - так профессионал ценит время свое и других.

По поводу "красивых концепций" - они не всегда совпадают с результатом. Если boost::spirit безумно крут, то чего Вам приходится прилагать заметные усилия для относительно несложной (и вполне типовой) задачи пропустить комменты?



Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 22, 2014, 13:29
Эээээ. Так m_ax не использует, надеюсь пока, spirit. :)
Здесь только токинайзер и регулярка.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 22, 2014, 15:03
Заметьте как резко возросла Ваша самооценка :) Вы уже знаете как пишут профессиональный код, смело считаете представления других наивными и.т.п.

А ведь это всего лишь один из возможных подходов. Полистайте напр исходники Bullet, а можно и просто Qt, и... о боже - никакого буста нет! Да и std если и найдется, то жалкие крохи. Как и во многих др уважаемых мною исходниках - и это не мешает им иметь большой успех.
Так я и говорю, что наивно пологать, что проффесиональный код - это код написанный "для дебилов". boost тому доказательство. Я ни чего не имею против Qt или Bullet )

Цитировать
Что мне не нравится в Вашем коде - что он требует неоправданных усилий для его понимания. Из первого десятка строк я ничего не извлекаю, то есть я понимаю сынтаксыс но не ф-ционал. Нужно смотреть дальше, только минут через 20 что-то проясняется - и то не вполне. Нет содержательных имен методов/вызовов за которые хотелось бы зацепиться, все свалено в операторы/итераторы. Как использовать этот код повторно? По-моему никак, он заточен на одну конкретную задачу.

Обычным оправданием приводится "общность", т.е. это работает и для std::string и для QString и еще для бог весть чего. Но тогда чего у Вас юзается char (ведь уникод гораздо больше в масть). И не слишком ли высока цена пресловутой "общности"? Чем не устраивал QString? Наверное хотелось "профессионально" - так профессионал ценит время свое и других.

Это всего лишь черновой вариант (первое приближение) где более важен сам подход. С общьностью проблем сейчас никаких нет. Немного причесал код.. теперь можете использовать и QString и std::string или что то своё..
Код
C++ (Qt)
#include <list>
#include <iterator>
#include <boost/regex.hpp>
#include <boost/range/istream_range.hpp>
#include <algorithm>
 
template <class BidirectIter, class Traits = std::iterator_traits<BidirectIter>>
class tex_iterator
{
public:
   typedef BidirectIter iterator;
   typedef typename Traits::value_type value_type;
   typedef typename Traits::pointer pointer;
   typedef typename Traits::reference reference;
   typedef typename Traits::difference_type difference_type;
   typedef typename std::bidirectional_iterator_tag iterator_category;
 
 
   typedef boost::basic_regex<value_type> regex_type;
 
   tex_iterator(iterator begin, iterator end, const regex_type & comment)
       : _begin(begin), _end(end), _it(begin), _comment(comment)
   {
       make_comments_list();
       if (_comments_list.begin()->begin() == _begin)
           ++*this;
   }
 
   tex_iterator() {}
 
   reference operator*() const { return *_it; }
 
   pointer operator->() const { return _it; }
 
   tex_iterator<BidirectIter, Traits>& operator++() {
       auto cur = _it;
       ++_it;
       for (const auto & comment : _comments_list) {
           if ((comment.begin() == _it) || (comment.begin() == cur)) {
               _it = comment.end();
               if (_it == _end)
                   break;
               ++_it;
           }
       }
 
       return *this;
   }
 
   tex_iterator<BidirectIter, Traits> operator++(int) {
       tex_iterator<BidirectIter, Traits> tmp = *this;
       ++*this;
       return tmp;
   }
 
   tex_iterator<BidirectIter, Traits>& operator--() {
       auto cur = _it;
       --_it;
       for (const auto & comment : _comments_list) {
           if ((comment.end() == _it) || (comment.end() == cur)) {
               _it = comment.begin();
               if (_it == _begin)
                   break;
               --_it;
           }
       }
 
       return *this;
   }
 
   tex_iterator<BidirectIter, Traits> operator--(int) {
       tex_iterator<BidirectIter, Traits> tmp = *this;
       --*this;
       return tmp;
   }
 
   template <class It, class T>
   friend bool operator==(const tex_iterator<It, T> &, const tex_iterator<It, T> &);
 
   template <class It, class T>
   friend bool operator!=(const tex_iterator<It, T> &, const tex_iterator<It, T> &);
 
private:
   iterator _begin;
   iterator _end;
   iterator _it;    //current iterator
   regex_type _comment;
   std::list<boost::iterator_range<iterator>> _comments_list;
 
   void make_comments_list() {
       if (_begin == _end)
           return;
 
       auto first = _begin;
       boost::match_results<iterator> what;
       while (boost::regex_search(first, _end, what, _comment)) {
           _comments_list.push_back(boost::iterator_range<iterator>(what[1].first, what[1].second));
           first = what[1].second;
       }
   }
};
 
template<class It, class T>
inline bool operator==(const tex_iterator<It, T> & x, const tex_iterator<It, T> & y) {
   return (x._it == y._it);
}
 
template<class It, class T>
inline bool operator!=(const tex_iterator<It, T> & x, const tex_iterator<It, T> & y) {
   return !(x == y);
}
 

Используется так:
Код
C++ (Qt)
   std::string str = "text1, #commented text\n text3,";
 
   tex_iterator<std::string::const_iterator> it(str.begin(), str.end(), boost::regex("(#[^\n]*)"));
   tex_iterator<std::string::const_iterator> end(str.end(), str.end(), boost::regex("(#[^\n]*)"));
 
   for (; it != end; ++it)
       std::cout << *it;
 

Почему не хочу QString:
во-первых не зочу тащить зависимости от Qt,
во-вторых, boost предоставляет более гибкие решения по разбору текста, чем Qt.
  
  


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 22, 2014, 15:05
Эээээ. Так m_ax не использует, надеюсь пока, spirit. :)
Здесь только токинайзер и регулярка.

Пока только изучаю)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 22, 2014, 15:54
Нет содержательных имен методов/вызовов за которые хотелось бы зацепиться, все свалено в операторы/итераторы.
Это вообще один итератор. Какие имена методов вы хотите видеть у итератора, когда у него есть только две поддерживаемые им операции: вперед и назад? ++/-- для вас малоинформативны?

Как использовать этот код повторно? По-моему никак, он заточен на одну конкретную задачу.
Его можно использовать везде, где может понадобиться пропускать области данных с заданными маркерами начала и конца.
Что еще можно требовать от маленького итератора? :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 22, 2014, 16:10
Old - как человек слабо осведомлённый о бусте я вам гарантирую - что нихрена непонятно :D И чтобы его преобразовать для моего "гипотетического" проекта мне нужно много времени. :)
Методов нет, всё упирается в буст и его знание :)

PS тот, кто уже изучил это - может поправить под свой проект. Кто не изучал - тому просто невыгодно суваться :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 22, 2014, 16:15
Методов нет, всё упирается в буст и его знание :)
Это заблуждение. :)
Итераторы это базовое понятие языка. Вы не можете разобраться с итераторами? Вы не знаете, что это такое?


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: _Bers от Апрель 22, 2014, 23:37
По впечатлению от беглого осмотра: код простой; читается легко.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 23, 2014, 09:07
Вроде код читается относительно не сложно.
По впечатлению от беглого осмотра: код простой; читается легко.
Я Вам верю. Но вот ситуация: автор кода сейчас отсутствует, а тут вылезла проблема, приходят файлы с др концами строк, не только \n как рассчитывалось
Код:
tex_string_iterator<char> ibegin(buffer.begin(), buffer.end(), '%', '\n');
Наверное Вам не составит труда изменить код так чтобы отрабатывались все 3 варианта  (\n, \r, \n\r).

Спасибо


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 23, 2014, 09:17
Наверное Вам не составит труда изменить код так чтобы отрабатывались все 3 варианта  (\n, \r, \n\r).
Конечно не составит. :)
Автор уже выложил причесанную версию с регулярками. :)

Мда, печально. Элементарный итератор вызывает огромные сложности, и это на программистском форуме. :(


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 23, 2014, 09:23
Вроде код читается относительно не сложно.
По впечатлению от беглого осмотра: код простой; читается легко.
Я Вам верю. Но вот ситуация: автор кода сейчас отсутствует, а тут вылезла проблема, приходят файлы с др концами строк, не только \n как рассчитывалось
Код:
tex_string_iterator<char> ibegin(buffer.begin(), buffer.end(), '%', '\n');
Наверное Вам не составит труда изменить код так чтобы отрабатывались все 3 варианта  (\n, \r, \n\r).

Спасибо

Да легко (вы последний вариант tex_iteratora смотрели?):
Код
C++ (Qt)
  boost::regex expr("(#[^\\n\\r]*)");
 
   std::string buffer = "AA, BB, C#DD, F\n++, D #Perl\r";
 
   tex_iterator<std::string::const_iterator> iter(buffer.begin(), buffer.end(), expr);
   tex_iterator<std::string::const_iterator> end(buffer.end(), buffer.end(), expr);
 
   for (; iter != end; ++iter)
       std::cout << *iter;
 


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 23, 2014, 16:27
Не все работают с итераторами. Я до последнего времени больше работал с UI, чем с внутренними механизмами.

И да, мне непонятна хренова туча буковок, которые называются итераторами :)

PS кто поставит мне в укор то, что я незнаю итераторы, тот пусть подумает и сам назовёт ту часть программирования в которой слаб. Всесторонне сильных не бывает, увы :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 23, 2014, 16:32
То что Вы высказываете свое мнение не боясь авторитетов - это радует. Но если Вы (неоднократно) даете уроки русского языка - пишите "не" правильно хотя бы с глаголами
незнаю итераторы


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 23, 2014, 16:36
PS кто поставит мне в укор то, что я незнаю итераторы
Я вам поставлю в укор не то, что вы не знаете, а то что не хотите узнать. Почитайте про них, хотя бы в википедии. :)
Это настолько просто, что вы сами удивитесь.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 23, 2014, 17:52
to Igors: Любители русского языка и граммофилы в шеренгу и шагом марш в прорубь.
to Old: простое знание итераторов у меня есть. Я знаю что это, даже простейшими std оперирую. А вот более сложного нет. Ибо нет реальной задачи для их использования :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 23, 2014, 17:54
А вот более сложного нет. Ибо нет реальной задачи для их использования :)
Вы не пользуетесь коллекциями? :)
Очень удобны для последовательного прохождения.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: xokc от Апрель 23, 2014, 19:25
Вы не пользуетесь коллекциями? :)
Я не пользуюсь в смысле совместно с итераторами. Не вижу от них реальных бонусов в своих задачах. Для последовательного прохождения использую foreach или for в контексте C++ 0x. Итераторный синтаксис меня лично коробит своей избыточностью.
Вам правда нравится писать так:
Код
C++ (Qt)
tex_iterator<std::string::const_iterator> iter(buffer.begin(), buffer.end(), expr);
Мне даже читать это неприятно, а писать - так уж и подавно. Ключевое слово auto в С++ 0x, конечно, несколько скрашивает этот кошмар, но, по моему, сама необходимость его присутствия в новом стандарте только подчеркивает нелепость (в синтаксическом смысле) таких языковых конструкций.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 23, 2014, 20:11
Возвёл очи к небу..  :'(


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 23, 2014, 20:33
Вам правда нравится писать так:
Конечно нет. :)
И для простого прохода по коллекции буду использовать for( auto v : collection ), пока мне не понадобиться внедриться в процесс движения указателя/курсора. А вот когда это понадобится, я создам итератор и буду использовать такую длинную запись.
Что такое итератор? Это, по сути, указатель на элемент коллекции, причём универсальный указатель. С ним могут работать все (имеются ввиду алгоритмы и функции). И если я хочу, что бы указатель научился новым фокусам, то я переопределяю его функционал. И могу использовать свой новый итератор в любом старом коде, более ничего не меняя.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 23, 2014, 20:34
Мне неприятен механизм их. Что нужны проверки на конец и т.п. Я уж лучше возьму, выясню длину, и точно пройду от и до for'ом.
update: и да, я могу использовать свой новый for в любом месте, где ток можно. Даже в С.



Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 23, 2014, 20:45
Я уж лучше возьму, выясню длину, и точно пройду от и до for'ом.
А если на момент начала прохода ещё нельзя получить всю длину или её вообще нельзя получить, потому что она постоянно изменяется? :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 23, 2014, 20:46
Значит или тут костыль, либо кривая архитектура :) Знать свою длину любой контейнер должен :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 23, 2014, 20:51
Значит или тут костыль, либо кривая архитектура :) Знать свою длину любой контейнер должен :)
Хотите со мной обсудить архитектуру, давайте.
Двухсвязный список, в него нитки воркеры постоянно добавляют записи, отдельная нитка движется по нему и обрабатывает записи определённого типа. Спрогнозировать ни количество добавляемые записей, ни среднее время обработки нужных записей невозможно.
Попробуете с фором? Или кривая архитектура? Расскажите как бы вы сделали?


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: xokc от Апрель 23, 2014, 21:20
Возвёл очи к небу..  :'(
И тем не менее. Понятно, что мы вновь радостно скатились в холивар, но вот есть проекты, код которых мной "принимается" как-то органично (типа Qt), а есть - ну вырви глаз просто (типа MFC/WinApi с их монстрами вроде
Код
C++ (Qt)
EnumServicesStatus(hSCM,SERVICE_WIN32, SERVICE_STATE_ALL, (LPENUM_SERVICE_STATUS)&Status, Size, &Needed, &Return, &Handle)
). Да и boost в этом смысле то ещё наслаждение:
Код
C++ (Qt)
boost::asio::async_write(socket_, boost::asio::buffer(data_, bytes_transferred), boost::bind(&session::handle_write, this, boost::asio::placeholders::error));
Только и годится для того, чтобы тут же свои обертки к этому кошмару написать и убрать эти художества по капот куда-нибудь поглубже.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 23, 2014, 21:25
Зачем использовать asio, если он не нравится? Есть 100500 всяких библиотек с "более традиционными" подходами. :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 23, 2014, 21:30
А зачем там фор?
Там есть воркеры, создающие элементы.
Там идёт обычный двусвязный список в который добавляются элементы.
Там идёт нитка читающая и обрабатывающая данные.
И просто у треда, держащего списочек должно быть замутексное изъятие первого элемента. Вот и всё.

Для более подробной архитектуры нужна более подробная информация об обработке. Меняются ли элементы оставаясь в списке, или же отдаются на сторону. Изымаются элементы или же модифицируются (2 предложения об 1 и том же с разных сторон :)).
Там не нужен фор как таковой. Там не нужен итератор как таковой.

И да, двусвязный список в любой момент времени скажет количество элементов. Нэ?


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 23, 2014, 21:36
Там не нужен фор как таковой. Там не нужен итератор как таковой.
Ага, а что там тогда нужно?
Вот есть список, там сейчас 1000 элементов, мы запускаем поток, который должен пробежаться по всему списку и обработать некоторые записи. В процессе его работы могут добавиться еще записи и их тоже он должен обработать.
Не нужно заморачиваться с синхронизацией, это ерунда.

И да, двусвязный список в любой момент времени скажет количество элементов. Нэ?
Ну и что? А через мгновенье оно будет другим. :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 23, 2014, 21:59
В данном случае мне неясно что он делает в обработке. Он модифицирует их или удаляет?
Тут вообще циклов ненужно. Зачем они? Собственно у нас есть класс с списком и он разруливает кто кому чего куда. Допустим список int.
В этом классе делаем метод getNext(). И спокойно проходим до конца списка.
В принципе с этой позиции очень похоже на итератор, но итератор не сможет работать одновременно с несколькими потоками, так что класс прослойка всё равно будет нужен. Потому итератор выбрасываем, оставляя только часть его функционала :) Остальное нам нафиг и не надо ^.^


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 23, 2014, 22:02
Ну вот вы сами и ответили на этот вопрос.
Теперь вам нужно посмотреть, а какой же функционал предоставляют базовые итераторы и вы избавитесь от предрассудков. :)
И главное, итератор это концепция, вы можете не использовать стандартные, но использовать свои. :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: _Bers от Апрель 23, 2014, 23:56
Зачем использовать asio, если он не нравится? Есть 100500 всяких библиотек с "более традиционными" подходами. :)

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

/зы
Ничего не имею против asio.
Просто любопытно, есть ли хоть одна альтернативная библиотека, по уровню не хуже asio.



Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: _Bers от Апрель 24, 2014, 00:08
Мне неприятен механизм их. Что нужны проверки на конец и т.п.
Я уж лучше возьму, выясню длину, и точно пройду от и до for'ом.
update: и да, я могу использовать свой новый for в любом месте, где ток можно. Даже в С.

Итератор - это паттерн. Суть которого: возможность единообразно пробежать по элементам любого контейнера, не зная принципов устройства этого контейнера.

Сам по себе механизм итерирования для них ничем не отличается от обычного цикла, в котором тупо перебираются элементы со стартового по конечный.




Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 24, 2014, 07:40
Да легко (вы последний вариант tex_iteratora смотрели?):
А может надо было не спешить и дать другим показать себя? Если это сделал автор (кстати с заметной переделкой версии) - это еще ни о чем не говорит.

Хорошо, а вот скажите: зачем применяются такие средства? Какой необходимостью и/или выгодой это вызвано? Что это за такой ужасный BibTex который нельзя впарить по-простому-народному? Открываем викусю
Цитировать
@Book{hicks2001,
 author    = "von Hicks, III, Michael",
 title     = "Design of a Carbon Fiber Composite Grid Structure for the GLAST
              Spacecraft Using a Novel Manufacturing Technique",
 publisher = "Stanford Press",
 year      =  2001,
 address   = "Palo Alto",
 edition   = "1st,",
 isbn      = "0-69-697269-4"
}
Хммм..... какие "итераторы" ??? Тут просто-напросто читать файл по строке и разбирать простейшими средствами, напр методами того же QString. За пару часов все готово (если не быстрее)

Откуда же взялось вот это?
Код
C++ (Qt)
template <class BidirectIter, class Traits = std::iterator_traits<BidirectIter>>
class tex_iterator
{
public:
   typedef BidirectIter iterator;
   typedef typename Traits::value_type value_type;
   typedef typename Traits::pointer pointer;
   typedef typename Traits::reference reference;
   typedef typename Traits::difference_type difference_type;
   typedef typename std::bidirectional_iterator_tag iterator_category;
 
   typedef boost::basic_regex<value_type> regex_type;
 
Мне кажется - просто из желания поумничать и покрасоваться, вот сотрите как я тут загнул! А тебе слабО так!  :). Это вполне простительная человеческая слабость, но к делу/работе это отношения не имеет, чисто понты


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 24, 2014, 08:24
Можете огласить список? (хотя бы парочку).
Начиная от курла: http://curl.haxx.se/ и
http://lacewing-project.org/
http://pocoproject.org/
http://www.alhem.net/Sockets/
http://www.w3.org/Library/
и заканчивая каким нибудь ACE. :)

Ничего не имею против asio.
Просто любопытно, есть ли хоть одна альтернативная библиотека, по уровню не хуже asio.
Мне asio очень нравиться и я пользуюсь только им, но на аналогичные решения посматриваю, если они мне попадаются.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 24, 2014, 08:26
Хорошо, а вот скажите: зачем применяются такие средства?
Какие средства? Итераторы? Вы спрашиваете зачем применять итераторы в C++?

Хммм..... какие "итераторы" ??? Тут просто-напросто читать файл по строке и разбирать простейшими средствами, напр методами того же QString. За пару часов все готово (если не быстрее)
Все правильно, на коленке по быстрому накидал и денег с заказчика взял, для чего думать, а что будет завтра, если придется что-то здесь менять? :)
К сожалению, не все так живут. Многим написанный сегодня код придется поддерживать и развивать еще очень долго, да еще и не одному. :)

"Всегда пишите код так, будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете."
— Martin Golding

Откуда же взялось вот это?
Так вас тайпдефы так напугали? :)
Сочувствую.
Вы раньше вроде писали, что операторы.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 24, 2014, 09:37
Цитировать
Хорошо, а вот скажите: зачем применяются такие средства? Какой необходимостью и/или выгодой это вызвано? Что это за такой ужасный BibTex который нельзя впарить по-простому-народному? Открываем викусю
Я повторяю десять раз и снова..

А теперь посмотрим на запись (BibTeXEntry) не из вики, а из реального журнала: https://journals.aps.org/prd/abstract/10.1103/PhysRevD.89.072015 (https://journals.aps.org/prd/abstract/10.1103/PhysRevD.89.072015)
Код
Bash
@article{PhysRevD.89.072015,
 title = {Updated cross section measurement of <span class="aps-inline-formula">
<math display="inline"><mrow><msup><mrow><mi>e</mi></mrow><mrow><mo>+</mo>
</mrow></msup><msup><mrow><mi>e</mi></mrow><mrow><mo></mo></mrow></msup>
<mo stretchy="false"></mo><msup><mrow><mi>K</mi></mrow><mrow><mo>+</mo></mrow>
</msup><msup><mrow><mi>K</mi></mrow><mrow><mo></mo></mrow></msup><mi>J</mi>
<mo stretchy="false">/</mo><mi>ψ</mi></mrow></math></span> and <span class="aps-inline-formula">
<math display="inline"><mrow><msubsup><mrow><mi>K</mi></mrow><mrow><mi>S</mi></mrow>
<mrow><mn>0</mn></mrow></msubsup><msubsup><mrow><mi>K</mi></mrow><mrow><mi>S</mi>
</mrow><mrow><mn>0</mn></mrow></msubsup><mi>J</mi><mo stretchy="false">/</mo><mi>ψ</mi></mrow></math></span> via initial state radiation at Belle},
 
 author = {Shen, C.\,P. and Yuan, C.\,Z. and Wang, P. and Abdesselam, A. and Adachi, I.
and Aihara, H. and Al Said, S. and Asner, D.\,M. and Aulchenko, V. and Aushev, T. and Ayad, R.
and Bakich, A.\,M. and Bala, A. and Bobrov, A. and Bonvicini, G. and Bozek, A.
and Bra\ifmmode \check{c}\else \v{c}\fi{}ko, M. and Browder, T.\,E. and Chekelian, V. and
Chen, A. and Cheon, B.\,G. and Chilikin, K. and Chistov, R. and Cho, K. and Chobanova, V. and
Choi, S.-K. and Choi, Y. and Cinabro, D. and Dalseno, J. and Danilov, M. and Dole\ifmmode \check{z}\else \v{z}\fi{}al, Z.
and Drutskoy, A. and Dutta, D. and Eidelman, S. and Epifanov, D. and Farhat, H. and Fast, J.\,E. and Ferber, T. and Frey, A.
and Gaur, V. and Ganguly, S. and Gillard, R. and Glattauer, R. and Goh, Y.\,M. and Golob, B. and Haba, J. and Hayasaka, K. and Hayashii, H. and He, X.\,H. and Hoshi, Y. and Hou, W.-S. and Hsiung, Y.\,B. and Hyun, H.\,J. and Iijima, T. and Ishikawa, A. and Itoh, R. and Iwasaki, Y. and Joffe, D. and Julius, T. and Kang, J.\,H.
and Kato, E. and Kawasaki, T. and Kiesling, C. and Kim, D.\,Y. and Kim, H.\,J. and Kim, J.\,B. and Kim, J.\,H.
and Kim, K.\,T. and Kim, M.\,J. and Kim, Y.\,J. and Kinoshita, K. and Ko, B.\,R.
and Kody\ifmmode \check{s}\else \v{s}\fi{}, P. and Korpar, S. and Kri\ifmmode \check{z}\else \v{z}\fi{}an, P. and Krokovny, P. and Kuzmin, A. and Kwon, Y.-J. and Lee, S.-H. and Li, J. and Li Gioi, L. and Libby, J. and Liu, C. and Liu, Z.\,Q. and Lukin, P.
and Matvienko, D. and Miyabayashi, K. and Miyata, H. and Mizuk, R. and Moll, A. and Mussa, R. and Nagasaka, Y. and Nakano, E. and Nakao, M. and Natkaniec, Z. and Nayak, M. and Nedelkovska, E. and Nisar, N.\,K. and Nishida, S. and Nitoh, O. and Okuno, S. and Park, C.\,W. and Park, H.
and Pedlar, T.\,K. and Pestotnik, R. and Petri\ifmmode \check{c}\else \v{c}\fi{}, M. and Piilonen, L.\,E. and Ritter, M.
and R\"ohrken, M. and Rostomyan, A. and Ryu, S. and Saito, T. and Sakai, Y. and Sanuki, T. and Sato, Y. and Schneider, O.
and Schnell, G. and Semmler, D. and Senyo, K.
and Seon, O. and Sevior, M.\,E. and Shapkin, M. and Shebalin, V. and Shibata, T.-A. and Shiu, J.-G.
and Shwartz, B. and Sibidanov, A. and Simon, F. and Sohn, Y.-S. and Sokolov, A. and Solovieva, E. and Stani\ifmmode \check{c}\else \v{c}\fi{}, S.
and Stari\ifmmode \check{c}\else \v{c}\fi{}, M. and Steder, M. and Sumiyoshi, T. and Tamponi, U.
and Tatishvili, G. and Teramoto, Y. and Uchida, M. and Unno, Y. and Uno, S. and Urquijo, P. and Usov, Y.
and Van Hulse, C. and Vanhoefer, P. and Varner, G.
and Vorobyev, V. and Wagner, M.\,N. and Wang, C.\,H. and Watanabe, M. and Watanabe, Y. and Williams, K.\,M. and Won, E. and Yamamoto, H.
and Yamashita, Y. and Yashchenko, S. and Yook, Y. and Zhang, C.\,C. and Zhang, Z.\,P. and Zhulanov, V. and Zupanc, A.},
 
 
 collaboration = {(Belle Collaboration)},
 journal = {Phys. Rev. D},
 volume = {89},
 issue = {7},
 pages = {072015}, %commented text, commented text,  
 numpages = {9},
 year = {2014},
 month = {Apr},
 publisher = {American Physical Society},
%  doi = {10.1103/PhysRevD.89.072015},
%  url = {http://link.aps.org/doi/10.1103/PhysRevD.89.072015},
}
 
И более того, в самом bib файле таких записей может быть сотни, может быть куча закомментированных блоков и т.д.. (кстатии, символ \% - не является началом комментария, в отличие от просто %)

Вот, для примера, моя реализация парсера, которая легко с этим справляется:
Код
C++ (Qt)
#ifndef BIBTEX_PARSER_H
#define BIBTEX_PARSER_H
 
#include <string>
 
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/regex.hpp>
#include <boost/tokenizer.hpp>
 
#include "core/spec_token_functions.h"
#include "core/tex_iterator.h"
#include "core/bibtex_entry.h"
 
namespace bibmake {
 
namespace core {
 
class bibtex_parser
{
public:
   typedef std::string string_type;
 
   template <class Iterator>
   static bool parse(Iterator begin, Iterator end, const string_type & key, bibtex_entry & entry)
   {
       static const boost::regex comment_regex("[^\\\\](%[^\\n\\r]*)");
 
       tex_iterator<Iterator> _begin(begin, end, comment_regex);
       tex_iterator<Iterator> _end(end, end, comment_regex);
 
       boost::match_results<tex_iterator<Iterator>> what;
       boost::regex regex("@(\\w+)[\\s\\t]*\\{[\\s\\t]*"+key);
 
       if (!boost::regex_search(_begin, _end, what, regex))
           return false;
 
       entry.set_key(key);
       entry.set_type(what.str(1));
 
       _begin = what[0].first;
 
       quote_list<char> quotes('{', '}');
       quotes.add_quote('"', '"');
 
       quote_extractor<char> qextractor(quotes);
       string_type _entry;
 
       if (!qextractor(_begin, _end, _entry))
           return false;
 
       boost::tokenizer<spec_char_separator<char>> tok(_entry, spec_char_separator<char>(",", "", quotes));
 
       regex.assign("[\\s\\t]*(\\w+)[\\s\\t]*=(.+)");
 
       for (auto s : tok)
       {
           boost::smatch w;
           if (boost::regex_search(s, w, regex))
           {
               string_type tag = boost::algorithm::to_lower_copy(w.str(1));
               string_type content = w.str(2);
               auto first = w[2].first;
               auto second = w[2].second;
               qextractor(first, second, content);
               boost::algorithm::trim(content);
               if (!content.empty())
                   entry.add_field(tag, content);
           }
       }
 
       return true;
   }
 
};
 
} /* namespace core */
 
} /* namespace bibmake */
 
#endif // BIBTEX_PARSER_H
 

Решение, которое предлагаете Вы, просто захлебнётся(

Во-вторых, кроме bibtexа нужно парсить ещё latex формат, откуда выдирать ключи на эти самые bibtex записи.. В этом тексте также могут быть комментарии, и целые их блоки.. Это неизбежно усложняет разбор этого формата.  Я об этом Вам уже тоже не раз писал..(

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

Неужели это так сложно понять?


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 24, 2014, 10:26
Вот, для примера, моя реализация парсера, которая легко с этим справляется:
Ваша реализация?
А скажите на милость, вот вы ушли гулять с собачкой, а в офисе остались только разносчик кофе и вахтерша баба Маша, как они должны будут исправить ваше решение, если вдруг позвонит заказчик? А?


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 24, 2014, 10:48
Вот, для примера, моя реализация парсера, которая легко с этим справляется:
Ваша реализация?
А скажите на милость, вот вы ушли гулять с собачкой, а в офисе остались только разносчик кофе и вахтерша баба Маша, как они должны будут исправить ваше решение, если вдруг позвонит заказчик? А?
;D
Ну им простительно) Для них программирование начинается и заканчивается на ХеллоВорлде)
А как известно, в ХеллоВорлде нет ни темплэйтов, ни итераторов, ни бустов, ни других вредных и избыточных непоймикаких концепций)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 24, 2014, 11:11
Код для сопровождения должен быть простым и самодокументируемым (ну или с комментариями), на программиста любого уровня, знающего C++.
Для вашего кода порог вхождения высок.
Для варианта Igors, который берётся на QString'e реализовать этот протокол, порог вхождения более низкий.

Т.е. ваш код - куча буков для меня на данный момент. Я не могу его поправить и/или изменить.
Код Igors будет для меня более понятен и я смогу его править на свой вкус, имея на руках только знание C++ и описание формата.

Сам сталкивался с таким, когда в одном проекте использовали S11n для сериализации/десереализации. Из-за сложности данных и их связи по 3-5 косвенным идентификаторам обычный его парсер не подходил. Я за день написал свой, по описанию, с нужными мне функциями. И (надеюсь) по сей день работает этот парсер, понятный каждому, кто умеет читать по английски и пользоваться Qt Assistant.
Обобщённость и универсальность это хорошо. Но она неизбежно приводит к усложнению конструкций языка :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 24, 2014, 11:20
И (надеюсь) по сей день работает этот парсер, понятный каждому, кто умеет читать по английски и пользоваться Qt Assistant.
А почему вы думаете, что Qt знают все. Вы предлагаете человеку, который знает C++ еще и Qt освоить?
А есть много программистов, которые негативно к нему относятся. Да и сам Qt не маленькая библиотечка, тащить его из-за вашего парсера?

Обобщённость и универсальность это хорошо. Но она неизбежно приводит к усложнению конструкций языка :)
А кто обещал, что будет легко? :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 24, 2014, 11:44
Во 1 поддержка кода в разы легче, когда не нужно специализированное знание чего-то.

Во 2 - Qt не знают всё. Зато надпись QString.replace опознает любой знающий программирование на 3-. А знающий на ровную 3 английский ещё и скажет, что этот метод делает. :)

В 3 - с помощью Assistant любой - повторюсь - ЛЮБОЙ человек распознает, что делает тот или иной метод. Это достижение троллей и это зверски удобное достижение. Сможете сказать, не солгал, что справка в Assistant по QString непонятнее, чем http://www.boost.org/doc/libs/1_55_0/libs/regex/doc/html/index.html.

В 4 - Qt являлось там стандартом для построения интерфейсов, так что тянуть его не надо было :) Оно и так имелось.

В 5 - вот именно начинается:
 1 - А вот здесь мы используем трехфазный матерчато-шоколадный генератор.
 2 - Но мы могли бы поставить простую AA батарейку.
 1 - Зато если в будущем, лет через 150, мы будем подключать эту хрень к возможно созданному нейрошлему, нам будет легче!
 2 - Но всё равно устройство то устареет, нужно будет создавать новое!
 1 - Отстать, никто не говорил что будет легко.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 24, 2014, 11:51
Во 2 - Qt не знают всё. Зато надпись QString.replace опознает любой знающий программирование на 3-. А знающий на ровную 3 английский ещё и скажет, что этот метод делает. :)
Вот это и печалит, что сейчас много кода делают не квалифицированные специалиста для не квалифицированных специалистов, и оправдывают это, тем что завтра может прийти еще менее квалифицированный специалист работать с этим кодом.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 24, 2014, 11:55
Не переживайте, хватит на ваш век профессионализма, а так - да. Великий код должен быть простым. Потому что когда ты неделю потеешь и только тогда понимаешь выверты кода - это значит, что программист который это писал не позаботился о тех, кто будет после него :) А значит не велик он :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 24, 2014, 12:01
Потому что когда ты неделю потеешь и только тогда понимаешь выверты кода - это значит, что программист который это писал не позаботился о тех, кто будет после него :) А значит не велик он :)
Т.е. если программист использовал шаблоны и этим значительно сократил размер исходного кода, и соответственно количество мест где могла быть ошибка, плох лишь потому, что школьник бездарь, который пришел после него не смог осилить шаблоны? Хорошая логика.
Ну что ж, ладно. :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 24, 2014, 12:01
Дело в том, Верес, что если такой "специалист" слепит этот парсер "по народному", как предлагает igors, то уверяю вас, разобраться и сопровождать  такую кашу будет гораздо сложнее(
И работать это (если и будет) то менее эффективно. И вероятность ошибок в таком коде будет большой.. поскольку любые малые изменения будут затрагивать всю логику..
  


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 24, 2014, 12:13
Если работа ведётся точно по описанию формата - да, проще. Если же формат имеет отклонениями и допущения, то наоборот. Не буду дальше спорить) Развлекайтесь.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 24, 2014, 12:25
Если работа ведётся точно по описанию формата - да, проще.
Аха, аха.. Уже представляю себе эти "if-else-if-else-switch" простые и универсальные народные решения  :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 24, 2014, 12:57
Решение, которое предлагаете Вы, просто захлебнётся(
Да никто не захлебнется если просто и нормально писать, без всяких выкрутасов. Напр
Код
C++ (Qt)
void CBib::ReadFile( CReader & reader )
{
while (reader.GetNextLine()) {
  switch (GetBibType(reader.mLine)) {
    case type_None:
      continue;
 
    case type_Book:
     mItems.push_back(new CBook());
     mItems.back()->Read(reader);
     break;
   ...
  }
}
}
Потом я так же распишу CBook::Read, возможно появятся методы ReadTitle и ReadAuthor. Какие проблемы? Кому что непонятно - я объясню. Какие "коленки" и проблемы с сопровождением? Чем мотивирован отказ от нормального рабочего кода в пользу чего-то "утонченного", "изысканного"? Это ж просто извращения!  :)

(кстатии, символ \% - не является началом комментария, в отличие от просто %)
Вот, для примера, моя реализация парсера, которая легко с этим справляется:
Отам вверху есть GetNextLine, в ней я найду в строке % и проверю предыдущий символ. А может и добавлю метод RemoveComments


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 24, 2014, 13:51
Цитировать
Да никто не захлебнется если просто и нормально писать, без всяких выкрутасов. Напр
Ой ли?
И получится у вас 100500 caseов на каждый тип.. А их там не мало и не факт что что-нибудь нового не добавят.. и придётся вам опять дописывать..
 
Цитировать
Потом я так же распишу CBook::Read, возможно появятся методы ReadTitle и ReadAuthor. Какие проблемы?
Потом Вы также допишите и CArticle::Read, CBooklet::Read, CInbook::Read, CIncollection::Read и так до кучи по всему списку..
А далее, дополнительно к Read нужно будет дописывать не только ReadTitle и ReadAuthor, но и другие не тривиальные аналогичные методы:
ReadNote, ReadAnnote, и т.д. до кучи..

В итоге у вас получается 100500 дополнительных классов и монстрообразные switch конструкции на 100500 строк.. И в случае чего: ищи switщи потом.. или ещё хуже дописывай новоиспечённый тип..

Цитировать
Какие проблемы? Кому что непонятно - я объясню. Какие "коленки" и проблемы с сопровождением? Чем мотивирован отказ от нормального рабочего кода в пользу чего-то "утонченного", "изысканного"?

Да, это действительно смешно) До слёз)

Цитировать
Отам вверху есть GetNextLine, в ней я найду в строке % и проверю предыдущий символ. А может и добавлю метод RemoveComments
А кто Вам сказал, что у вас будет возможность работать с файлом? Например у вас на входе string.. Подождите, я угадаю: напишите ещё один Reader? Парсер ничего не должен знать ни о каких ридерах..

Вобщем, грустно всё это(


   

 


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 24, 2014, 13:55
Чем мотивирован отказ от нормального рабочего кода в пользу чего-то "утонченного", "изысканного"? Это ж просто извращения!  :)
А чем мотивирован объектной ориентированный подход по сравнению с процедурным?
Вот вы показали классический процедурный подход, а m_ax - ОО.
А дальше каждый решает сам, какой подход для него ближе и гибче. Тут пока не по чувствуешь - не поймешь.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Hrundel от Апрель 24, 2014, 23:07
Чем мотивирован отказ от нормального рабочего кода в пользу чего-то "утонченного", "изысканного"? Это ж просто извращения!  :)
А чем мотивирован объектной ориентированный подход по сравнению с процедурным?
Вот вы показали классический процедурный подход, а m_ax - ОО.
А дальше каждый решает сам, какой подход для него ближе и гибче. Тут пока не по чувствуешь - не поймешь.
Если используются объекты и классы - это уже в любом случае ООП.
Принципы Ноймана никто не отменял, поэтому написание методов не может быть иным, кроме как "классический процедурный подход", как вы это называете.
Процедурное программирование в Qt, в принципе не возможно. Даже при написании консольных приложений.
При этом оба понятия относятся не к подходам, а к парадигмам.
В подходах же, отличают: агентно-ориентированный подход(JADE), компонентно-ориентированное программирование(.NET) и прототипное(JavaScript).
И это подходы не столько к программированию, сколько к структуре языка.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 24, 2014, 23:47
Я сторонник такого кода, который может понять любой человек с помощью книг и/или помощи. А итераторы, как я убеждаюсь на своём опыте, требуют больше практики и меньше теории :D


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: _Bers от Апрель 25, 2014, 00:09
Начиная от курла: http://curl.haxx.se/ и
http://lacewing-project.org/
http://pocoproject.org/
http://www.alhem.net/Sockets/
http://www.w3.org/Library/
и заканчивая каким нибудь ACE. :)

Мне asio очень нравиться и я пользуюсь только им, но на аналогичные решения посматриваю, если они мне попадаются.

Спасибо. Я сохранил себе ссылочки



Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: _Bers от Апрель 25, 2014, 00:23
Я сторонник такого кода, который может понять любой человек с помощью книг и/или помощи. А итераторы, как я убеждаюсь на своём опыте, требуют больше практики и меньше теории :D

Сложность кода слагается из различных ингредиентов. Например, таких как: синтаксическая сложность, алгоритмическая, архитектурная, и тп.

Синтаксическая - оказывает наименьшее влияние.

Кстати, я видел код, который не содержал никаких "технологических штучек".
Если взять отдельно взятую функцию - синтаксис понятный и узнаваемый.
Вот только что они делают не совсем понятно, потому что алгоритмическая сложность равномерно размазалась по всему проекту.
Что бы понять алгоритм одной функции, нужно было знать детали о других функциях.
Тоже самое касалось архитектуры.

Что бы понять такой код, потребовалось потратить время на изучение: что оно делает, и как она это делает.
Для этого сначала логгировал стек вызовов функций, что бы проследить "что делает".
И только потом заглядывал в пошаговой отладке вовнутри, что бы понять "как делает".
Учитывая значительный объем кода, это все заняло немало времени.

Исследование более "технологического", но более лаконичного, сжатого в объеме кода обходится быстрее.

А итераторы: что такого сложного вы в них находите?

Найдите десять отличий:
 http://rextester.com/LDUG16618


Код:
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    cout << "Hello, world!\n";

    const int ar[]={1,2,3,4,5,6};   
    const vector<int> vec(ar, ar+6);
   
    {
        const auto beg = ar+1;
        const auto end = ar+4;
        for(auto it = beg; it!=end; ++it)
            cout<<"it = "<<*it<<endl;
    }
    cout<<"-------\n";
    {   
        const auto beg = vec.begin()+1;
        const auto end = vec.begin()+4;
        for(auto it = beg; it!=end; ++it)
            cout<<"it = "<<*it<<endl;
    }

}


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 25, 2014, 03:14
Если используются объекты и классы - это уже в любом случае ООП.
Это большое заблудение: "я написал в своей программе class, значит я автоматически пишу ОО-программу". Это совсем не так. Так же как и "язык C++ это С с классами". Это два совершенно разных языка, отличающимися с самого начала - с момента проектирования программы.
Скажите, вот вы взяли программу на С и стали в ней использовать контейнер вектор, стала ли она от этого объектно-ориентированной?
Я уже несколько раз писал на форуме, чем ОО подход отличается от процедурного. Кстати, очень легко можно писать ОО-программы на С, так-же как процедурные на С++.
И очень хорошо расставляет в голове эти все вещи Гради Буч. Если не читали обязательно прочтите.

Принципы Ноймана никто не отменял, поэтому написание методов не может быть иным, кроме как "классический процедурный подход", как вы это называете.
Ну и что? Что из этого, по вашему, следует, что ООП не существует? :)

Процедурное программирование в Qt, в принципе не возможно. Даже при написании консольных приложений.
Еще одно заблуждение.
Если вы все процедуры поместите в класс MainWindow и назовете их методами, то ваша программе не станет от этого объектно-ориентированной.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 25, 2014, 06:56
И на С можно писать объектно ориентированно при помощи процедур. Это подход, а не конструкции языка.

to _Bers итераторы std мне понятны и просты. Итераторы аля те, что привёл ТС - непонятны.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 25, 2014, 07:42
И на С можно писать объектно ориентированно при помощи процедур. Это подход, а не конструкции языка.
Точно.
Причем подход даже не к самому кодированию на языке, а раньше, к проектированию.

to _Bers итераторы std мне понятны и просты. Итераторы аля те, что привёл ТС - непонятны.
Это потому, что вы не захотели разобраться. Вам проще сказать себе: "нет, мне это не надо".
На самом деле это они же, те самые простые итератора, только с дополнительными фокусами.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 25, 2014, 09:00
Потом Вы также допишите и CArticle::Read, CBooklet::Read, CInbook::Read, CIncollection::Read и так до кучи по всему списку..
А далее, дополнительно к Read нужно будет дописывать не только ReadTitle и ReadAuthor, но и другие не тривиальные аналогичные методы:
ReadNote, ReadAnnote, и т.д. до кучи..
Совершенно верно, допишу. Если чтение однотипно - обобщу. Нет - переживу.

В итоге у вас получается 100500 дополнительных классов и монстрообразные switch конструкции на 100500 строк.. И в случае чего: ищи switщи потом.. или ещё хуже дописывай новоиспечённый тип..
Классов там и десятка не наберется. Switch-ей тоже. А дописывать новый тип придется всем. И добавить это в switch куда легче чем ковыряться в итераторах.

А кто Вам сказал, что у вас будет возможность работать с файлом? Например у вас на входе string.. Подождите, я угадаю: напишите ещё один Reader? Парсер ничего не должен знать ни о каких ридерах..
Это утверждение безосновательно. Чем плохо если есть возможность работать строка за строкой? Наоборот хорошо, тем более если интересующая информация в виде "вкраплений" в большой документ.

Да, это действительно смешно) До слёз)
...
Вобщем, грустно всё это(
Возможно именно это чаще всего отталкивает от буста - его зашкаливающая переоценка тех кто "прикоснулся к прекрасному". Др решения и в подметки не годятся. Те кто не юзает дуст - жалкие велосипедисты :) Только вот результатами это не подтверждается. Более того - часто все наоборот. Я уверен: делали бы Вы "в стиле начинающего" - все давным-давно было бы готово и уже забыто. А так Вы до сих пор копаетесь в подробностях итератора. Ну и вообще "задирать нос" нехорошо  :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: xokc от Апрель 25, 2014, 09:03
Это потому, что вы не захотели разобраться. Вам проще сказать себе: "нет, мне это не надо".
Так об этом-то и речь! До тех пока я не пойму, что мне это действительно надо, зачем мне в этом разбираться?
Только ради приобщения к касте суровых мужиков программистов, непременно использующих итераторы для всякого последовательного обхода коллекции?


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 25, 2014, 09:18
Так об этом-то и речь! До тех пока я не пойму, что мне это действительно надо, зачем мне в этом разбираться?
А как вы сможете понять, что "оно вам очень надо", если не прикоснетесь к этому? :)
Вот вы решаете задачу, так как привыкли и делали это много раз, но вы можете не догадываться, что эту же задачу можно решить красивее, универсальный и короче, просто потому что не смотрите по сторонам. И это очень грустно, потому что прогресса нет.
Я лезу во все, что мне попадается, и думаю как и когда мне это может пригодиться. В дальнейшем, я перебираю варианты подходов к решению, проверяю, гоняю тесты и принимаю решение. Обратите внимание, я говорю именно о подходах, а не о готовых решениях и библиотеках.

Вот пример, разбор сложного тестового формата.
Процедурный подход превратит код в ад (switch & if) даже если придется обрабатывать несколько десятков тегов, а если еще и будут зависимости, что один тег должен идти обязательно после другого, а тот  перед третьим, то понять и сопровождать это будет не возможно.
ОО подход, упростит решение, за счет того, что обработчики тегов будут независимыми объектами, упрятанными в разные классы + он будет легко расширяем, просто добавлением и регистрированием новых объектов-обработчиков.
А подход с boost.spirit, это третий подход, позволяющий описать лексические правила разбора потока (как в том же flex) и задать при необходимости правила, что делать с данными при разборе. Он сам будет проверять правильность источника по этим правилам, сам будет вызывать обработчики данных и т.д. Этот подход позволит значительно упростить разработку и сопровождение такого проекта, добавлять и модифицировать правила очень просто.

Вот три подхода, на самом деле их еще больше. Но если вы всегда пользовались первым и не интересовались, а как это еще можно решать, до остальных вариантов вы можете не дойти никогда. :)
А представьте, что вам поставили задачу разбора и проверки на отсутствие ошибок исходников того же C++? Кто сможет реализовать такое с процедурным подходом? :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Bepec от Апрель 25, 2014, 09:43
У меня нет задачи под итераторы с фокусами. Тупо нет. Есть похожие задачи, но их архитектура не требует никаких итераторов с фокусами.
Чтобы понять бустовские нужно дня два сидеть и разбираться, набрасывать проектики и вот... в конце концов понять, что велосипед был проще? Увольте.
Вот возникнет задача в которой велосипед не будет справляться, или будет справляться плохо - тогда буду искать другие решения. Ведь при написании велосипедов я узнаю больше, чем при использовании буста :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 25, 2014, 10:00
У меня нет задачи под итераторы с фокусами. Тупо нет. Есть похожие задачи, но их архитектура не требует никаких итераторов с фокусами.
Чтобы понять бустовские нужно дня два сидеть и разбираться, набрасывать проектики и вот... в конце концов понять, что велосипед был проще? Увольте.
Вот возникнет задача в которой велосипед не будет справляться, или будет справляться плохо - тогда буду искать другие решения. Ведь при написании велосипедов я узнаю больше, чем при использовании буста :)
Блин, а кто говорит про буст?
Я говорю о разных подходах к решению. У вас нет задач под итераторы с фокусами, потом что вы не знаете, что они могут уметь дополнительные фокусы, а не потому, что их нет на самом деле. Вот и выходит, что вы всегда будете решать задачу одним методом, который знаете.

Это заблуждение, что при написании велосипеда, вы узнаете больше. Вы будете из раза в раз использовать QString и его split, ну может еще регулярку добавите. И каждое новое решение ничем не будет отличаться от старого, только именами тегов и их обработчиков. :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: xokc от Апрель 25, 2014, 10:14
А как вы сможете понять, что "оно вам очень надо", если не прикоснетесь к этому? :)
...
Но если вы всегда пользовались первым и не интересовались, а как это еще можно решать, до остальных вариантов вы можете не дойти никогда. :)
А представьте, что вам поставили задачу разбора и проверки на отсутствие ошибок исходников того же C++? Кто сможет реализовать такое с процедурным подходом? :)
Ну для начала, я не говорил, что принципиально не использую современные техники программирования. Я говорил, что не гонюсь за ними до тех пор, пока не не осознаю, что с ними моя задача не решится "лучше" (легче, компактнее, быстрее, дешевле и т.п.). Предвосхищая очередной аргумента в стиле "откуда знаешь если сам не пробовал", процитирую классиков "Не обязательно пробовать г...но, чтобы понять каково оно на вкус". Несколько грубовато и неправильно характеризует объект спора, но вполне применимо к уровню аргументации.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 25, 2014, 10:24
процитирую классиков "Не обязательно пробовать г...но, чтобы понять каково оно на вкус".
Не верный аргумент. Вы правда считаете, что все что является г..ном для вас, на самом деле г..но? :) Вот Igors и Верес считают итераторы г..ном, итераторы от этого становятся г..ном? :)
Я никого не заставляю и не навязываю, что то использовать, я просто советую смотреть по сторона и пробовать даже, на первый взгляд, безумные решения. Они могут оказаться тем что надо. :)



Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: OKTA от Апрель 25, 2014, 10:25
Хватит уже спорить  ;D
Удобочитаемость и скорость разработки увеличивают большинство нововведений в языке, но к сожалению ни одно еще не увеличивало скорости итоговой работы программы ;D


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 25, 2014, 10:38
А подход с boost.spirit, это третий подход, позволяющий описать лексические правила разбора потока (как в том же flex) и задать при необходимости правила, что делать с данными при разборе. Он сам будет проверять правильность источника по этим правилам, сам будет вызывать обработчики данных и т.д. Этот подход позволит значительно упростить разработку и сопровождение такого проекта, добавлять и модифицировать правила очень просто.
Ну а чего же "по-сухому"? Вот BitTex в рамках гуглы, для удобства привожу опять
Цитировать
@Book{hicks2001,
 author    = "von Hicks, III, Michael",
 title     = "Design of a Carbon Fiber Composite Grid Structure for the GLAST
              Spacecraft Using a Novel Manufacturing Technique",
 publisher = "Stanford Press",
 year      =  2001,
 address   = "Palo Alto",
 edition   = "1st,",
 isbn      = "0-69-697269-4"
}
Покажите как это распарсить спиритом, тогда и сравним. 


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 25, 2014, 10:40
Покажите как это распарсить спиритом, тогда и сравним.  
Покажите как вы это распарсите процедурно, а я покажу как это распарсить spirit.
Давайте, только то что m_ax выложил, реальный пример. :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: OKTA от Апрель 25, 2014, 10:55
И скорость, скорость обязательно замерьте!  ;D


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 25, 2014, 11:00
Покажите как вы это распарсите процедурно, а я покажу как это распарсить spirit.
Давайте, только то что m_ax выложил, реальный пример. :)
Ну вот Вы и ответили :) То есть вот так "достать из широких штанин" не получится. Усилия все равно придется прилагать, даже владея хорошими тулзами. Как минимум структуры данных набросать, правила куда-то приткнуть и.т.п., набежит немало. Поэтому речь идет о сокращении кода/усилий. Окупит ли оно себя? На таком простом примере (и даже на приведенном m_ax) - нет, лобовое решение дешевле.

Что касается более сложных задач (типа синтаксис С++) - то да, там лезть в лоб неуместно. Ну придется что-то "привлекать", напр Scintilla содержит парсеры для неск десятков языков.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 25, 2014, 11:03
Ну вот Вы и ответили :) То есть вот так "достать из широких штанин" не получится. Усилия все равно придется прилагать, даже владея хорошими тулзами.
Конечно. Глупо думать, что имея хороший инструментарий, ничего не надо делать. Я вам про это постоянно говорю. :)

нет, лобовое решение дешевле.
Традиционное голословное утверждение, непонятно откуда взявшееся. Давайте проверим. Выкладывайте свое решение. :)

Я так понимаю, что книг в этот формате в сети полно, на чем тестировать есть. Вот и погоняем.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 25, 2014, 11:20
Цитировать
Я так понимаю, что книг в этот формате в сети полно, на чем тестировать есть.
С радостью предоставлю материал для тестов)
Если до тестов, вообще, дойдёт.. Что то боюсь, простое народное решение от igors мы так и не увидим( 


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: xokc от Апрель 25, 2014, 12:31
Вы правда считаете, что все что является г..ном для вас, на самом деле г..но? :)
Правда НЕ считаю. Поэтому специально написал:
Несколько грубовато и неправильно характеризует объект спора, но вполне применимо к уровню аргументации.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: kamre от Апрель 25, 2014, 12:41
Видно, что итераторы не любят некоторые. А что скажете насчет boost::range (http://www.boost.org/doc/libs/1_55_0/libs/range/doc/html/range/concepts/overview.html), насколько удобно пользоваться по сравнению с for/iterators?


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 25, 2014, 13:01
Давайте проверим. Выкладывайте свое решение. :)
Я так понимаю, что книг в этот формате в сети полно, на чем тестировать есть. Вот и погоняем.
С радостью предоставлю материал для тестов)
Если до тестов, вообще, дойдёт.. Что то боюсь, простое народное решение от igors мы так и не увидим( 
Это тоже до боли знакомо: ну вот как-то не срослась "умность великая" - и все льется на простака который делает :) Ну да ладно, мне тоже интересно проверить. Только вот делать за m_ax всю работу = некорректно, речь об ограниченном примере. Поэтому гоните ТЗ в котором будет

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

Разумеется исходим из правила "не указал в ТЗ - свободен". Со своей стороны обещаю к ТЗ сильно не придираться и найду время чтобы сделать - ну не "сию минуту", но в ближайшие неск дней.

Если кто еще желает поучаствовать - welcome


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 25, 2014, 13:45
Видно, что итераторы не любят некоторые. А что скажете насчет boost::range (http://www.boost.org/doc/libs/1_55_0/libs/range/doc/html/range/concepts/overview.html), насколько удобно пользоваться по сравнению с for/iterators?
Где примерчик который можно тупо передрать? Нету - ну так и нафиг оно надо?
Лоховской подход? Безусловно :) Прекрасно понимаю что буст ничего просто так не делал бы. Во всех редких случаях когда мне пришлось использовать буст (в основном для работы с полигонами) результаты были просто изумительны. НО - зачем мне надо прилагать усилия без всякой на то необходимости? Программист должен (и обязан) быть "ленивым"  :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 25, 2014, 14:46
Это тоже до боли знакомо: ну вот как-то не срослась "умность великая" - и все льется на простака который делает :) Ну да ладно, мне тоже интересно проверить. Только вот делать за m_ax всю работу = некорректно, речь об ограниченном примере. Поэтому гоните ТЗ в котором будет

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

Разумеется исходим из правила "не указал в ТЗ - свободен". Со своей стороны обещаю к ТЗ сильно не придираться и найду время чтобы сделать - ну не "сию минуту", но в ближайшие неск дней.

Если кто еще желает поучаствовать - welcome

Ссылка на описание bibtex формата: http://www.bibtex.org/Format/ (http://www.bibtex.org/Format/)
Плюс поддержка комментариев:
символ начало комментария %
символ конца комментария - конец строки
однако \% - началом комментария не является.

По поводу примера: Выкладываю файлик: bibliography.bib, который содержит 4 записи (bibtex_entry)

По поводу структуры данных:
На выходе мы должны иметь список записей bibtex entry.

bibtex_entry должна иметь:
1) key
2) type
3) список полей (tag = content)

Вот возможная реализация:
Код
C++ (Qt)
struct bibtex_entry
{
   std::string citation_key; // for example: @article{citation_key, ...
 
   std::string type; // article, book, inbook, etc.
 
   std::map<std::string, std::string> fields // tag = content
};
 

У нас есть файл с библиографией (bibliography.bib), мы его читаем и на выходе получаем список (list, vector etc.) bibtex_entry

Вообщем то и всё)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: _Bers от Апрель 25, 2014, 22:50
И на С можно писать объектно ориентированно при помощи процедур. Это подход, а не конструкции языка.

Приведите пожалуйста, простейший пример оо-кода на языке си.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 26, 2014, 00:33
Ну вроде разбирает. :)

m_ax, небольшие вопросы:
Как я понял, citation_key это не обязательное поле и может отсутствовать?
Что вообще делать с не комментарием \%, где он может находится, как я понял, только в параметрах полей?


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 26, 2014, 09:02
Причесал парсер, добавил комментарии описывающие правила разбора.
Все вместе с main занимает 163 строки, это с моим размашистым стилем, если убрать пустые строки, думаю будет где-то 100.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 26, 2014, 09:24
Ну вроде разбирает. :)

m_ax, небольшие вопросы:
Как я понял, citation_key это не обязательное поле и может отсутствовать?
Что вообще делать с не комментарием \%, где он может находится, как я понял, только в параметрах полей?

Нет, citation key обязателен - без него не сослаться на публикацию.. 

Да, если символ \% встретится в поле (content) то он интерпретируется как значёк процента, а не как начало комментария.   


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 26, 2014, 09:33
Нет, citation key обязателен - без него не сослаться на публикацию.. 
Все, уже обязателен. :)

Да, если символ \% встретится в поле (content) то он интерпретируется как значёк процента, а не как начало комментария.   
Ok, тогда я правильно все понял.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 27, 2014, 09:34
В аттаче моя реализация на базе QString :) Выделен базовый класс CReader, он ничего не знает о Bib.  Задумка такая: парсить по строкам обычно проще/приятнее, их можно пропускать, отсечь комменты до конца строки не проблема, можно сразу сделать trim и.т.п. Но с др стороны нужны операции захватывающие неск строк. Напр прочитать все в кавычках или в скобках. Вот это CReader и делает.

Ну а порожденный CBibReader уже парит специфику BibTex. Никаких трудностей я не испытал  :)



Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 27, 2014, 09:52
А вот решение с использованием boost.spirit:
Код
C++ (Qt)
#include <string>
#include <map>
#include <fstream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/operators.hpp>
 
using namespace std;
using namespace boost::spirit;
namespace ph = boost::phoenix;
namespace sn = boost::spirit::standard_wide;
 
// ===================================================================================
 
typedef string String;
typedef pair<String, String> Field;
typedef map<String, String> FieldList;
 
struct Entry
{
String type; // article, book, inbook, etc.
String citation_key; // for example: @article{citation_key, ...
FieldList fields; // tag = content
 
void dump()
{
cout << "-------------------------------------" << endl
<< "Type: " << type << endl
<< "Key : " << citation_key << endl;
for( auto v : fields )
cout << v.first << " = " << v.second << endl;
}
};
 
BOOST_FUSION_ADAPT_STRUCT(
Entry,
(String, type)
(String, citation_key)
(FieldList, fields)
)
 
// ===================================================================================
template <class ForwardIterator, class Skipper>
class Parser : public qi::grammar<ForwardIterator, Entry(), Skipper>
{
public:
Parser() : Parser::base_type( m_start, "Parser" )
{
// Документ может состоять из мусора и записей
m_start = m_junk >> m_entry;
 
// Мусор это любые символы кроме @
m_junk = *~qi::lit( '@' );
// Запись начинается с @ и содержит тип записи и тело, которое находится между {}
m_entry = '@' >>
m_type[ ph::at_c<0>( _val ) = _1 ] >>
'{' >> m_body[ ph::at_c<1>( _val ) = ph::at_c<0>( _1 ), ph::at_c<2>( _val ) = ph::at_c<1>( _1 ) ] >> '}';
 
// Тип это несколько букв и/или цифр
m_type = +sn::alnum;
// Тело содержит ключ и набор полей
m_body = m_citation_key >> ',' >> m_fields >> -qi::lit( ',' );
 
// Ключ это любые символы до запятой
m_citation_key = qi::lexeme[ +(~qi::char_( ',' ) - sn::space) ];
// Набор полей состояит из нескольких полей
m_fields = -( m_field % ',' );
 
// Поле содержит ключ и значение
m_field = m_key >> '=' >> m_value;
 
m_key = qi::lexeme[ +(~qi::char_( "=,})" ) - sn::space) ];
m_value = m_quoted | +~qi::char_( ",})#" );
 
m_quoted = qi::lexeme[ ( '"' >> *m_innerQuoteText >> '"' ) | ( '{' >> *m_innerBraceText >> '}' ) ]
[ _val = ph::accumulate(_1, ph::construct<std::string>()) ];
 
m_innerQuoteText %= qi::as_string[ qi::char_('{') >> *(m_innerQuoteText | m_escapedText) >> qi::char_('}') ] | m_quoteText;
m_innerBraceText %= qi::as_string[ qi::char_('{') >> *(m_innerBraceText | m_escapedText) >> qi::char_('}') ] | m_escapedText;
 
m_quoteText = +( m_escapedQuote | ~qi::char_("\"{}") );
m_escapedText = !qi::lit('{') >> +( m_escapedBrace | ~qi::char_("{}") );
 
m_escapedBrace.add
("\\{", '{')
("\\}", '}')
;
m_escapedQuote.add
("\\\"", '"')
;
}
 
private:
typedef boost::fusion::vector<String,FieldList> BodyParam;
 
qi::symbols<char, char> m_escapedBrace;
qi::symbols<char, char> m_escapedQuote;
 
qi::rule<ForwardIterator, Entry(), Skipper> m_start;
qi::rule<ForwardIterator, Skipper> m_junk;
qi::rule<ForwardIterator, Entry(), Skipper> m_entry;
qi::rule<ForwardIterator, String(), Skipper> m_type;
qi::rule<ForwardIterator, BodyParam(), Skipper> m_body;
qi::rule<ForwardIterator, String(), Skipper> m_citation_key;
qi::rule<ForwardIterator, FieldList(), Skipper> m_fields;
qi::rule<ForwardIterator, Field(), Skipper> m_field;
qi::rule<ForwardIterator, String(), Skipper> m_key;
qi::rule<ForwardIterator, String(), Skipper> m_value;
qi::rule<ForwardIterator, String(), Skipper> m_quoted;
qi::rule<ForwardIterator, String()> m_innerQuoteText;
qi::rule<ForwardIterator, String()> m_innerBraceText;
qi::rule<ForwardIterator, String()> m_quoteText;
qi::rule<ForwardIterator, String()> m_escapedText;
};
 
// ===================================================================================
 
template<class ForwardIterator, class Skipper, class Container>
inline bool read( ForwardIterator first, ForwardIterator last, Skipper& s, Container& e,
 boost::enable_if<boost::is_same<typename Container::value_type, Entry> >* /*dummy*/ = NULL )
{
Parser<ForwardIterator, Skipper> p;
return qi::phrase_parse(first, last, *p, s, e );
}
 
// ===================================================================================
 
int main( int argc, char *argv[] )
{
if( argc < 2 )
{
cerr << "Using: bibparser file.bib" << endl;
return 1;
}
 
string filename = argv[ 1 ];
cout << "Parsing file: " << filename << endl;
 
ifstream is( filename );
is.unsetf( ios_base::skipws );
if( !is )
{
cerr << "Error open source file" << endl;
return 1;
}
 
boost::spirit::istream_iterator beg( is );
boost::spirit::istream_iterator end;
 
deque<Entry> e;
 
auto space = sn::space | '%' >> *(qi::char_ - qi::eol) >> qi::eol;
 
cout << "result = " << read( beg, end, space, e ) << endl;
 
for( auto v : e )
v.dump();
 
return 0;
}
 


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 27, 2014, 13:13
Погонял у себя все три варианта: мой, old и igors.

Всё же на мой взгляд, решение с использованием Spirit самоё ёмкое и гибкое. Надо будет украсть его с небольшими переделками)

Что касается производительноти, то сделал три замера на время парсинга одного своего старого bib файла, где 126 записей.
Результаты такие:
Код
C++ (Qt)
int main()
{
 
   const char * filename = "bibliography.bib";
 
   std::ifstream in(filename);
   std::ostringstream oss;
   oss << in.rdbuf();
 
   std::string buff = oss.str();
   std::list<bibtex_entry> entrys;
 
   auto start = std::chrono::high_resolution_clock::now();
   bibtex_parser::parse(buff.cbegin(), buff.cend(), entrys);
   auto stop = std::chrono::high_resolution_clock::now();
   auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop-start).count();
 
   std::cout << "m_ax: parsing time, (ms) = " << duration << std::endl;
   std::cout << "number of entries = " << entrys.size() << std::endl << std::endl;
 
 
 
   std::vector<Entry> e;
 
   auto space = sn::space | '%' >> *(qi::char_ - qi::eol) >> qi::eol;
 
   start = std::chrono::high_resolution_clock::now();
   read( buff.cbegin(), buff.cend(), space, e );
   stop = std::chrono::high_resolution_clock::now();
   duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop-start).count();
 
   std::cout << "old: parsing time, (ms) = " << duration << std::endl;
   std::cout << "number of entries = " << e.size() << std::endl << std::endl;
 
 
 
   QFile bibFile(filename);
   if (!bibFile.open(QIODevice::ReadOnly))
       return -1;
 
   QList <CBibTag> theBib;
   CBibReader reader(bibFile);
 
   start = std::chrono::high_resolution_clock::now();
   while (reader.ReadLine()) {
       int type;
       QString citeKey;
       if (!reader.BibStart(type, citeKey)) continue;
 
       theBib.push_back(CBibTag(type, citeKey));
 
   }
   stop = std::chrono::high_resolution_clock::now();
   duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop-start).count();
 
   std::cout << "igors: parsing time, (ms) = " << duration << std::endl;
   std::cout << "number of entries = " << theBib.size() << std::endl << std::endl;
 
   return 0;
}
 

Код
Bash
m_ax: parsing time, (ms) = 26
number of entries = 126
 
old: parsing time, (ms) = 9
number of entries = 126
 
igors: parsing time, (ms) = 11
number of entries = 123
 
---------------------------------------------------------------------------
m_ax: parsing time, (ms) = 22
number of entries = 126
 
old: parsing time, (ms) = 5
number of entries = 126
 
igors: parsing time, (ms) = 10
number of entries = 123
 
---------------------------------------------------------------------------
m_ax: parsing time, (ms) = 20
number of entries = 126
 
old: parsing time, (ms) = 7
number of entries = 126
 
igors: parsing time, (ms) = 13
number of entries = 123
 
 

Пока не стал разбираться почему у igors выдаёт только 123 записи вместо 126..
Вечером ещё погоняю и отпишусь.)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: _Bers от Апрель 27, 2014, 14:15
Я бы не стал доверять замерам сделанным
 auto start = std::chrono::high_resolution_clock::now();



Недавеча только человек выкладывал в тырнетах вопрос:

два цикла делаеют одно и тоже. Первый цикл - сырые указатели. Второй - смартпоинтеры

Смартпоинтеры оказались быстрее..

Затем меняем местами циклы: сначала по смартам, потом по сырым - сырые оказались быстрее.

Проявляется стабильно.

Муть какая то.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 27, 2014, 16:52
Что касается производительноти, то ...
Здесь я, признаться, удивлен. Ожидал что мой вариант будет медленнее минимум на порядок - ведь QString довольно расходен/затратен.

Пока не стал разбираться почему у igors выдаёт только 123 записи вместо 126..
Наверняка это я где-то насвистел. Не суть, все требует отладки/тестирования, это нормально. Важно что показаны 3 разных подхода к решению одной задачи - и это интересно. Кстати - а где Ваш?

Я бы не стал доверять замерам сделанным
Ну чего Вы все о мелочах? Что язык Вы знаете изрядно - всем ясно. А вот во что это выливается.. Ваше "технологическое" решение не хотите показать?  :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 27, 2014, 18:02
Цитировать
Наверняка это я где-то насвистел.
Конечно Вы)

Цитировать
Не суть, все требует отладки/тестирования, это нормально.
Да, а если отлаживать Ваш код придётся кому-нибудь другому? Или слегка изменить функциональность?
Вот здесь как нельзя кстатии задать этот вопрос, которой стал причиной этой темы..

Цитировать
Кстати - а где Ваш?

Свой я уже показывал:
Код
C++ (Qt)
#ifndef BIBTEX_PARSER_H
#define BIBTEX_PARSER_H
 
#include <string>
 
#include <boost/algorithm/string/trim.hpp>
#include <boost/regex.hpp>
#include <boost/xpressive/xpressive.hpp>
#include <boost/tokenizer.hpp>
 
#include "core/spec_token_functions.h"
#include "core/skipper_iterator.h"
#include "core/bibtex_entry.h"
 
namespace bibmake {
 
namespace core {
 
class bibtex_parser
{
public:
   typedef std::string string_type;
 
   template <class Iterator, class Container>
   static size_t parse(Iterator begin, Iterator end, Container & entry_list)
   {
       if (begin == end)
           return 0;
 
       using namespace boost::xpressive;
       basic_regex<Iterator> comment = (~as_xpr('\\') | bos) >> (s1 = ('%' >> *(~_n) >> (_n | eos)));
 
       boost::regex start_entry_regex("@(\\w+)[\\s\\t]*\\{");
 
       basic_regex<Iterator> field = *space >> (s1 = +_w) >> *space >> '=' >> (s2 = +_);
 
       quote_list<char> quotes('{', '}');
       quotes.add_quote('"', '"');
       quote_extractor<char> qextractor(quotes);
 
       skipper_iterator<Iterator> _begin(begin, end, comment);
       skipper_iterator<Iterator> _end(end, end, comment);
 
       boost::match_results<skipper_iterator<Iterator>> what;
       size_t counter(0);
       while (boost::regex_search(_begin, _end, what, start_entry_regex))
       {
           bibtex_entry entry;
           entry.set_type(what.str(1));
 
           _begin = what[1].second;
           string_type fields;
           if (!qextractor(_begin, _end, fields))
           {
               _begin = what[1].second;
               continue;
           }
 
           boost::tokenizer<spec_char_separator<char>> tok(fields, spec_char_separator<char>(",", "", quotes));
           auto it = tok.begin();
           if (it == tok.end())
                continue;
 
           entry.set_key(boost::algorithm::trim_copy(*it));
           ++it;
 
           for (; it != tok.end(); ++it)
           {
               smatch w;
               if (regex_search(*it, w, field))
               {
                   string_type tag = w.str(1);
                   string_type content = w.str(2);
                   auto first = w[2].first;
                   auto second = w[2].second;
                   if (!qextractor(first, second, content))
                       content = w.str(2);
                   boost::algorithm::trim(content);
                   if (!content.empty())
                       entry.add_field(tag, content);
               }
           }
           entry_list.push_back(entry);
           ++counter;
       }
 
       return counter;
   }
 
};
 
} /* namespace core */
 
} /* namespace bibmake */
 
#endif // BIBTEX_PARSER_H
 

Сейчас ещё поковыряю тесты..


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 27, 2014, 18:04
Я бы не стал доверять замерам сделанным
 auto start = std::chrono::high_resolution_clock::now();

Ну мне главное хотя бы по порядку величины время оценить)
Даже не само время, а то, как они соотносятся между разными реализациями, хотя бы примерно..   


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 27, 2014, 18:12
Свой я уже показывал:
Вы уверены что это весь код? Не вижу "приемника" - т.е. структур должны заполняться (получать считанные данные)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 27, 2014, 18:21
Свой я уже показывал:
Вы уверены что это весь код? Не вижу "приемника" - т.е. структур должны заполняться (получать считанные данные)

Это код парсера. Плюс есть ещё bibtex_entry. Приёмник данных это любой контейнер (например std::list<bibtex_entry>) у которого есть метод push_back.
skipper_iterator Вы уже видели (изменилось только то, что сейчас он использует не regex, а xpressive), о расширениях boost::tokenizer мы уже тоже говорили в теме "разбор QString"

Вот bibtex_entry:
Код
C++ (Qt)
#ifndef BIBTEX_ENTRY_H
#define BIBTEX_ENTRY_H
 
#include <string>
#include <map>
#include <boost/algorithm/string/case_conv.hpp>
 
namespace bibmake {
 
namespace core {
 
class bibtex_entry
{
public:
   typedef std::string string_type;
   typedef std::map<string_type, string_type> fields_type;
   typedef typename fields_type::size_type size_type;
   typedef typename fields_type::const_iterator const_iterator;
 
   bibtex_entry() {}
 
   string_type key() const { return m_key; }
 
   string_type type() const { return m_type; }
 
   void set_type(const string_type & type)
   {
       m_type = boost::algorithm::to_lower_copy(type);
   }
 
   void set_key(const string_type & key)
   {
       m_key = key;
   }
 
   void add_field(const string_type & tag, const string_type & content)
   {
       m_fields[boost::algorithm::to_lower_copy(tag)] = content;
   }
 
   void erase(const string_type & tag)
   {
       m_fields.erase(boost::algorithm::to_lower_copy(tag));
   }
 
   string_type content(const string_type & tag) const
   {
       auto it = m_fields.find(boost::algorithm::to_lower_copy(tag));
       return (it != m_fields.end()) ? it->second : string_type();
   }
 
   bool is_contains(const string_type & tag) const
   {
       return (m_fields.find(boost::algorithm::to_lower_copy(tag)) != m_fields.end());
   }
 
   size_type size() const { return m_fields.size(); }
 
   bool empty() const { return m_fields.empty(); }
 
   const_iterator begin() const { return m_fields.begin(); }
 
   const_iterator end() const { return m_fields.end(); }
 
private:
   string_type m_key;
   string_type m_type;
   fields_type m_fields;
};
 
} /* namespace core */
 
} /* namespace bibmake */
 
#endif // BIBTEX_ENTRY_H
 
 

Или о каком приёмнике данных идёт речь?


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 27, 2014, 20:12
Немного наврал с результатами теста..
В предыдущем варианте у igors при парсенге я случайно убрал строчку
Код
C++ (Qt)
if (!reader.ReadBibTag(theBib.back()))
                   theBib.pop_back();
 
 
где происходит заполнение записи..

Сейчас результаты такие:
Код
Bash
m_ax: parsing time, (ms) = 18
number of entries = 126
 
old: parsing time, (ms) = 4
number of entries = 126
 
igors: parsing time, (ms) = 22
number of entries = 123
 
-------------------------------------------------------------------
m_ax: parsing time, (ms) = 20
number of entries = 126
 
old: parsing time, (ms) = 12
number of entries = 126
 
igors: parsing time, (ms) = 16
number of entries = 123
 
-------------------------------------------------------------------
m_ax: parsing time, (ms) = 18
number of entries = 126
 
old: parsing time, (ms) = 9
number of entries = 126
 
igors: parsing time, (ms) = 21
number of entries = 123
 
 

Во-вторых, igors, у Вас поля (content) содержатся внутри  цитат, а они должны быть извлечены из них { .. }
vмелочь, но тем не менее..


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 27, 2014, 20:25
Ну раз пошла такая пьянка, то решил набросать парсер для 3d-файлов obj.
Весь парсер - это 40 строк кода!
Код
C++ (Qt)
template <class ForwardIterator, class Skipper>
class ObjParser : public qi::grammar<ForwardIterator, Skipper, ModelData()>
{
public:
ObjParser() : ObjParser::base_type( m_start )
{
using boost::phoenix::at_c;
 
m_start = *(
m_vertex_lst[ at_c<0>(_val) = _1 ] |
m_normal_lst[ at_c<1>(_val) = _1 ] |
m_texcoord_lst[ at_c<2>(_val) = _1 ] |
m_face_lst[ at_c<3>(_val) = _1 ]
) >> qi::eoi;
 
m_vertex_lst = m_vertex >> *m_vertex;
m_vertex = lit( "v" ) >> double_[ at_c<0>(_val) = _1 ] >> double_[ at_c<1>(_val) = _1 ] >> double_[ at_c<2>(_val) = _1 ] >> -double_[ at_c<3>(_val) = _1 ];
 
m_normal_lst = m_normal >> *m_normal;
m_normal = lit( "vn" ) >> double_[ at_c<0>(_val) = _1 ] >> double_[ at_c<1>(_val) = _1 ] >> double_[ at_c<2>(_val) = _1 ];
 
m_texcoord_lst = m_texcoord >> *m_texcoord;
m_texcoord = lit( "vt" ) >> double_[ at_c<0>(_val) = _1 ] >> double_[ at_c<1>(_val) = _1 ] >> -double_[ at_c<2>(_val) = _1 ];
 
m_face_lst = m_face >> *m_face;
m_face = lit( "f" ) >> m_index >> m_index >> m_index >> *m_index;
m_index = int_[ at_c<0>(_val) = _1 ] >> -( '/' >> -int_[ at_c<1>(_val) = _1 ] >> -( '/' >> int_[ at_c<2>(_val) = _1 ] ) );
}
 
private:
qi::rule<ForwardIterator, Skipper, ModelData()> m_start;
qi::rule<ForwardIterator, Skipper, VertexList()> m_vertex_lst;
qi::rule<ForwardIterator, Skipper, Vertex()> m_vertex;
qi::rule<ForwardIterator, Skipper, NormalList()> m_normal_lst;
qi::rule<ForwardIterator, Skipper, Normal()> m_normal;
qi::rule<ForwardIterator, Skipper, TexCoordList()> m_texcoord_lst;
qi::rule<ForwardIterator, Skipper, TexCoord()> m_texcoord;
qi::rule<ForwardIterator, Skipper, FaceList()> m_face_lst;
qi::rule<ForwardIterator, Skipper, Face()> m_face;
qi::rule<ForwardIterator, Skipper, Index()> m_index;
};
 

Парсер разбирает следующие блоки: вертексы, нормали, текстурные координаты, индексы поверхностей (учитывая необязательные поля).
Причем, индексы обрабатывает все: вертексов, нормалей и тестурных координат.
Нормально обрабатывает отсутствие каких-то индексов:
f 1 2 3
f 1/1 2/2 3/3
f 1/1/1 2/2/2 3/3/3
f 1//1 2//2 3//3
Точек в поверхности может быть больше трех.
Не надо говорить, что с комментариями тоже все в порядке. :)

Этот парсер заполняет структуру ModelData:
Код
C++ (Qt)
struct Vertex
{
explicit Vertex() : x( 0. ), y( 0. ), z( 0. ), w( 1. ) {}
explicit Vertex( double vx, double vy, double vz, double vw = 1 ) : x( vx ), y( vy ), z( vz ), w( vw ) {}
 
double x;
double y;
double z;
double w;
};
 
struct Normal
{
explicit Normal() : x( 0. ), y( 0. ), z( 0. ) {}
explicit Normal( double vx, double vy, double vz ) : x( vx ), y( vy ), z( vz ) {}
 
double x;
double y;
double z;
};
 
struct TexCoord
{
explicit TexCoord() : u( 0. ), v( 0. ), w( 0. ) {}
explicit TexCoord( double vu, double vv, double vw = 0 ) : u( vu ), v( vv ), w( vw ) {}
 
double u;
double v;
double w;
};
 
struct Index
{
explicit Index() : v( -1 ), vn( -1 ), vt( -1 ) {}
explicit Index( int vv, int vvn, int vvt ) : v( vv ), vn( vvn ), vt( vvt ) {}
 
int v;
int vn;
int vt;
};
 
typedef deque<Vertex> VertexList;
typedef deque<Normal> NormalList;
typedef deque<TexCoord> TexCoordList;
typedef deque<Index> Face;
typedef deque<Face> FaceList;
 
struct ModelData
{
VertexList v;
NormalList vn;
TexCoordList vt;
FaceList f;
};
 

Если нужно обрабатывать другие данные из формата, то правила для них легко добавляются в разбор. /* Я хотел вначале показать разбор только вертексов, но остальное легко добавилось в процессе. :) */


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Апрель 27, 2014, 21:54
Да, Spirit рулит)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 28, 2014, 08:27
Причем, индексы обрабатывает все: вертексов, нормалей и тестурных координат.
Нормально обрабатывает отсутствие каких-то индексов:
Не вижу как - ведь должно быть 3 контейнера индексов (позиция, текстура, нормаль). Пара противных мелочей

1) строки могут быть склеены, напр полигон с 5 вертексами может быть записан так
Цитировать
f 1/1 2/2 3/3  \
4/6 6/7 5/4 

2) возможны такие индексы
Цитировать
f -1 -2 -3
Это значит "от текущего", напр на данный момент прочитано 100 позиций, значит реальные индексы (99, 98, 97). К сожалению не удается отложить это на потом т.к. "текущий" может измениться

Но все равно - впечатляет, круто



Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 28, 2014, 08:51
Не вижу как - ведь должно быть 3 контейнера индексов (позиция, текстура, нормаль).
Информация по каждому индексу хранится в структуре Index, а они уже лежат в контейнере.

1) строки могут быть склеены
Это не проблема. :)

2) возможны такие индексы
В спецификации по формату я такого не увидел, хотя я смотрел его через строчку.
Покажите, где про это написано.

А так, это тоже не проблема. :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 28, 2014, 09:25
Информация по каждому индексу хранится в структуре Index, а они уже лежат в контейнере.
Ага, вижу. Но тут дека нехороша т.к. полигоны с большим числом вертексов редки. А для стандартных треугольников затрачивается 512 (gсс) байт для хранения 3 * 3 * sizeof(int). Вообще оbj файл задуман для хранения 3 независимых "пространств", поэтому лучше 3 контейнера.

Это не проблема. :)
...
А так, это тоже не проблема. :)
Верю, но как? :) Было бы интересно посмотреть

Покажите, где про это написано.
Напр здесь http://www.martinreddy.net/gfx/3d/OBJ.spec (http://www.martinreddy.net/gfx/3d/OBJ.spec)
Цитировать
   v is a reference number for a vertex on the line. A minimum of two
    vertex numbers are required. There is no limit on the maximum.
    Positive values indicate absolute vertex numbers. Negative values
    indicate relative vertex numbers.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 28, 2014, 09:31
Но тут дека нехороша
Вы можете изменить тип контейнера на любой желаемый, больше ничего менять не придется.

Верю, но как? :) Было бы интересно посмотреть
Когда доберусь до компьютера переделаю и покажу.
Склейку через '\' уже сделал, просто добавил в правила скипера выкусываение этого символа. :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 28, 2014, 21:35
Когда доберусь до компьютера переделаю и покажу.
Думаю, что заставлять парсер корректировать номера индексов не совсем верно, не его это задача. Но как это можно сделать покажу чуть ниже.

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

А это один из возможных вариантов решения по корректировки индексов самим парсером:
Код
C++ (Qt)
// Изменяем структуру списка поверхностей
// Добавляем метод addFace, в котором проверяем передаваемые индексы,
// корректируем их при необходимости и добавляем в коллекцию
struct FaceList : public deque<Face>
{
void addFace( const Face &f )
{
cout << "addFace" << endl;
push_back( f );
}
};
 
// И меняем правило получения списка поверхностей
// Теперь, после разбора всех индексов одного face, будет вызываться наш метод addFace, в котором мы все будем фиксить
// Правило можно упростить, перейдя на форму записи списков (%), но тогда потребуется еще кое что менять - лень.
m_face_lst = m_face[ boost::phoenix::bind( &FaceList::addFace, _val, _1 ) ] >> *m_face[ boost::phoenix::bind( &FaceList::addFace, _val, _1 ) ];
 


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: xokc от Апрель 28, 2014, 22:32
Код
C++ (Qt)
m_face_lst = m_face[ boost::phoenix::bind( &FaceList::addFace, _val, _1 ) ] >> *m_face[ boost::phoenix::bind( &FaceList::addFace, _val, _1 ) ];
 
И вы реально считаете, что так должен выглядеть современный код на C++?


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 29, 2014, 05:35
И вы реально считаете, что так должен выглядеть современный код на C++?
Конечно нет, точнее не обязательно. :)
Это демонстрация специализированного инструмента для решения определенного круга задач.
Т.е. если разбор текстов для человека типовая задача, которую он постоянно решает, то можно воспользоваться spirit, предварительно разобравшись с ним. Он сможет значительно облегчить процесс написания парсеров.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 29, 2014, 10:57
Как я вижу себе это сейчас, парсер разбирает данные из файла в структуру ModelData, дальше уже модель может разложить их, например, по векторам (точный размер данных у нас есть и мы можем сразу получить нужный кусок без переаллокаций) или собрать все данные по вертексам в одну структуру и сложить их в список. При этом, мы легко сможем корректировать индексы, если они отрицательные.
Не понял. Да, было бы хорошо сделать это "потом" (когда все считано), но тогда утерян "текущий" индекс вертекса (см пример что я приводил выше).

Вообще складывать все в контейнеры не есть хорошо, точнее не есть задача парсера. Сам парсер "ничего не должен знать" о формате данных. Считав "единицу информации" (напр вертекс, фейсет) он должен вызвать метод класса напр "model", а тот уж разберется что с этой единицей делать. Иначе получается конверсия в нужный формат - не смертельно, но плюс еще работа.

Теперь чуть более сложные вещи: хотя нумерация вертексов всегда неуклонно нарастает, в файле есть объекты/группы.  Пример (источник тот же)
Цитировать
    g front cube
    f 1 2 3 4
    g back cube
    f 8 7 6 5
    g right cube
    f 4 3 7 8
    g top cube
    f 5 1 4 8
    g left cube
    f 5 6 2 1
    g bottom cube
    f 2 6 7 3
    # 6 elements
Визуально кубик тот же, но вместо 6 фейсов в 1 объекте на выходе должно быть 6 объектов по 1 фейсе в каждом. Имена объектов должны быть предъявлены юзверю. Как это сделать на спирите?

Спасибо


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 29, 2014, 11:11
Не понял. Да, было бы хорошо сделать это "потом" (когда все считано), но тогда утерян "текущий" индекс вертекса (см пример что я приводил выше).
Почему он утерян, у нас все индексы лежат строго в том же порядке что и в файле.

Вообще складывать все в контейнеры не есть хорошо, точнее не есть задача парсера. Сам парсер "ничего не должен знать" о формате данных.
Здесь ModelData это промежуточный формат данных.
Парсер знает только его, но ничего не знает про модель/загрузчик. А модель/загрузчик ничего не знает про парсер, но знает ModelData.

Считав "единицу информации" (напр вертекс, фейсет) он должен вызвать метод класса напр "model", а тот уж разберется что с этой единицей делать.
Тогда парсер будет знать про класс Model, и жестко привязан к ее методам. :)

Но если сильно хочется, то я выше показал как можно вызывать методы.

Визуально кубик тот же, но вместо 6 фейсов в 1 объекте на выходе должно быть 6 объектов по 1 фейсе в каждом. Имена объектов должны быть предъявлены юзверю. Как это сделать на спирите?
Добавляем структуру группа, которая будет хранить имя и список поверхностей.
И добавляем правило, что-то типа:
m_group = lit( "g" ) >> m_name >> m_faceList;


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 29, 2014, 13:45
Тогда парсер будет знать про класс Model, и жестко привязан к ее методам. :)
Это нормально, еще лучше сделать интерфейс модели (ограничить познания парсера).

Добавляем структуру группа, которая будет хранить имя и список поверхностей.
И добавляем правило, что-то типа:
m_group = lit( "g" ) >> m_name >> m_faceList;
Да, но как это "синхронизировать"? Собственно проблема та же самая что и с отрицательными индексами. Пример:

В какой-то момент приходит "g" или индекс < 0 или "usemtl" и.т.п.. При "ручном" разборе нам известно: сейчас (на данный момент) считано столько-то вертексов и фейсетов, поэтому не составляет труда  сменить принимающие контейнеры ("g"), пересчитать индекс, завести материал и.т.п. Но как это сделать в spirit где все идет "одной струей"? Ведь допустив дальнейшее чтение мы теряем счетчики, "поезд уйдет"

Еще подобный вопрос: куда/как пристроить индикатор для юзверя с возможностью отмены? В общем, хотелось бы не только "правила", но и удобные callback'и, без них прожить трудно, какая-то бяка да найдется

Спасибо



Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 29, 2014, 16:49
Это нормально, еще лучше сделать интерфейс модели (ограничить познания парсера).
Ну я не считаю это нормальным.
Парсер - это маленькая подсистемка загрузки ресурсов (скорее всего закрытая) и знакомить ее с публичным классом из совершенно другой подсистемы считаю неправильным и очень вредным. И совершенно не важно будет использоваться интерфейс или нет.
К тому же, не всегда целесообразно делать в модели публичные методы для ее модификации на примитивном уровне: добавить текстурную координату, добавить нормаль. В моделе могут быть более высокоуровневые методы для этого.
А сейчас ModelData это закрытая внутренняя структура, которую можно менять как угодно, ведь про неёзнают только внутренности загрузчика и модели.

Да, но как это "синхронизировать"?
Тут нужно разобраться, как сработает это правило:
m_group = lit( "g" ) >> m_name >> m_faceList;

Сначала будет найдено имя команды 'g', дальше будет проверено и загружено имя группы, а потом правило будет ждать описание одного или нескольких фейсов. Только когда все это будет соблюдено правило отработает и мы получим на выходе заполненную структуру Group.
Код
C++ (Qt)
struct Group
{
   string    name;
   FaceList faces;
};
 

Тоже самое с материалами, вы описываете полное правило, начиная от usemtl, потом могут идти такие то параметры. А на выходе получите готовую структуру Material.

Еще подобный вопрос: куда/как пристроить индикатор для юзверя с возможностью отмены? В общем, хотелось бы не только "правила", но и удобные callback'и, без них прожить трудно, какая-то бяка да найдется
Ну так итераторы же. :)
Он знает начало, конец и текущее положение. А также всегда может послать исключение или перейти в конец, для завершения парсинга.
Или написать специализированный парсер, который встраивать в главное правило разбора.



Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Igors от Апрель 30, 2014, 10:13
Тоже самое с материалами, вы описываете полное правило, начиная от usemtl, потом могут идти такие то параметры. А на выходе получите готовую структуру Material.
В том-то и дело что получать нечего - там нет ничего кроме имени. Но эта строка меняет контекст дальнейшего разбора. Как я делал руками: получив "usemtl mat1"

- проверяю есть ли материал с таким именем std::map<std::string, int>. Если нет - добавляю. В любом случае получаю уникальный ID материала и устанавливаю его как текущий.

- у фейса есть доп поле materialID, оно = индексу текущего материала (хотя в самой строке "f" этой инфы нет)

Ситуация с группой/объектом и др та же самая. Идеально было бы чтобы spirit заливал не в контейнеры, а в локальные структуры и после каждого чтения отдавал управление мне. Как это сделать?

Спасибо


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 30, 2014, 10:16
В том-то и дело что получать нечего - там нет ничего кроме имени.
Ну так правило смотрит не только одну строку, она будет просматривать все последующие строки и определять параметры, которые относятся к материалу.
Вы думаете строками - не надо. Нужно думать правилами. :)

Дальше пока не читал. :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Апрель 30, 2014, 10:21
в локальные структуры и после каждого чтения отдавал управление мне. Как это сделать?
Ну так это уже есть.

Например это правило:
Код
C++ (Qt)
m_vertex = lit( "v" ) >> double_[ at_c<0>(_val) = _1 ] >> double_[ at_c<1>(_val) = _1 ] >> double_[ at_c<2>(_val) = _1 ] >> -double_[ at_c<3>(_val) = _1 ];
заполняет структуру Vertex, дальше вы можете вызвать свой метод, передав эту структуру в качестве параметра.
Как я уже показал на примере метода addface.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Май 03, 2014, 22:45
Переписал сейчас BibTeX parser на Spiritе.. Всё работает и всё хорошо, но возникло пара вопросов.. По поводу прикручивания erreor handling..

Суть в следующем:
Пусть имеется bib файл с записями.. Если в одной из записей (bibtex_entry) что то пошло не так, то все последующие записи игнорируются и парсинг прекращается(

И это в общем то понятно..
 Хорошо, это проблема решается, если повесить на грамматику error handling (обработку ошибок).. Тогда в лог выводится вся информация о том где и что было сделано неправильно..

Но хочется следующей реакции: Попадается дифектная запись (bibtex_entry), далее выводится сообщение в лог (игнорируя эту запись), и далее процесс парсинга продолжается (а не останавливается). Эдакий оптимистический вариант.. Чёрт с ней с этой записью, но главное, чтобы после неё  все распарсились..

Сейчас сделано так:
Код
C++ (Qt)
#ifndef BIBTEX_PARSER_H
#define BIBTEX_PARSER_H
 
#include <string>
 
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/fusion/include/map.hpp>
 
#include "core/bibtex_entry.h"
 
namespace bibmake {
 
namespace core {
 
using namespace boost::spirit;
namespace phx = boost::phoenix;
namespace sw = boost::spirit::standard_wide;
 
namespace detail {
 
template <class Logger>
class logger_wrapper_impl
{
public:
   logger_wrapper_impl(const Logger & logger) : _logger(logger) {}
 
   template <class, class, class, class>
   struct result
   {
       typedef void type;
   };
 
   template <class Iterator, class String>
   void operator()(const String & what,
                   Iterator it_1,
                   Iterator it_2,
                   Iterator it_3) const
   {
       _logger(what, it_1, it_2, it_3);
   }
 
private:
   const Logger & _logger;
};
 
struct default_logger
{
   template <class Iterator, class String>
   void operator()(const String & what, Iterator /*it_1*/, Iterator it_2, Iterator it_3) const
   {
       std::cerr   << "Error! Expecting "
                   << what
                   << " here: \""
                   << std::string(it_2, it_3)
                   << "\""
                   << std::endl;
   }
};
 
} /* namrspace detail */
 
template <class ForwardIterator>
class inner_brace_text : public qi::grammar<ForwardIterator, std::string()>
{
public:
   inner_brace_text() : inner_brace_text::base_type(start_)
   {
       escaped_brace_ = qi::char_('\\') >> qi::char_;
 
       simple_text_ = +(escaped_brace_ | ~qi::char_("{}"));
 
       inner_brace_text_ %= simple_text_
               |
               qi::as_string
               [
               qi::char_('{') >> *(inner_brace_text_ | simple_text_) >> qi::char_('}')
               ];
 
       start_ %= '{' >> qi::omit[*sw::space] >> *inner_brace_text_ >> qi::omit[*sw::space] >> '}';
   }
 
private:
   qi::rule<ForwardIterator, std::string()> simple_text_, inner_brace_text_, escaped_brace_, start_;
};
 
 
template <class ForwardIterator>
class inner_quote_text : public qi::grammar<ForwardIterator, std::string()>
{
public:
   inner_quote_text() : inner_quote_text::base_type(start_)
   {
       escaped_quote_ = qi::char_('\\') >> qi::char_;
 
       inner_quote_text_ = +(escaped_quote_ | ~qi::char_('"'));
 
       start_ %= '"' >> qi::omit[*sw::space] >> *inner_quote_text_ >> qi::omit[*sw::space] >> '"';
   }
 
private:
   qi::rule<ForwardIterator, std::string()> inner_quote_text_, escaped_quote_, start_;
};
 
 
template <class ForwardIterator, class Skipper>
class bibtex_parser : public qi::grammar<ForwardIterator, bibtex_entry(), Skipper>
{
public:
   template <class Logger = detail::default_logger>
   bibtex_parser(const Logger & logger = detail::default_logger()) : bibtex_parser::base_type(start_, "BibTeX Parser")
   {
       type_ = +qi::alpha;
 
       key_ = +(qi::alnum | qi::char_("-_:/"));
 
       tag_ = +(qi::alnum | qi::char_("-_:/"));
 
       simple_content_ = +qi::alnum;
 
       content_ = inner_brace_content_ | inner_quote_content_ | simple_content_;
 
       body_ = '{' > key_ > ',' > fields_ >> -qi::lit(',') > '}';
 
       fields_ = -(field_ % ',');
 
       field_ = tag_ > '=' > content_;
 
       start_ = *~qi::lit('@') >> qi::lit('@')
               >>
               type_[phx::at_c<0>(_val) = _1]
               >>
               body_
               [
                   phx::at_c<1>(_val) = phx::at_c<0>(_1),
                   phx::at_c<2>(_val) = phx::at_c<1>(_1)
               ];
 
 
       start_.name("start");
       body_.name("body");
       fields_.name("fields");
       field_.name("field");
       type_.name("type");
       key_.name("citation key");
       tag_.name("tag");
       content_.name("content");
 
       phx::function<detail::logger_wrapper_impl<Logger>> logger_wrapper = detail::logger_wrapper_impl<Logger>(logger);
 
       qi::on_error<qi::fail>(start_, logger_wrapper(_4, _1, _3, _2));
   }
 
private:
   qi::rule<ForwardIterator, bibtex_entry(), Skipper> start_;
   qi::rule<ForwardIterator, std::pair<std::string, bibtex_entry::fields_type>(), Skipper> body_;
   qi::rule<ForwardIterator, bibtex_entry::fields_type(), Skipper> fields_;
   qi::rule<ForwardIterator, std::pair<std::string, std::string>(), Skipper> field_;
   qi::rule<ForwardIterator, std::string()> type_;
   qi::rule<ForwardIterator, std::string()> key_;
   qi::rule<ForwardIterator, std::string()> tag_;
   inner_brace_text<ForwardIterator> inner_brace_content_;
   inner_quote_text<ForwardIterator> inner_quote_content_;
   qi::rule<ForwardIterator, std::string()> simple_content_;
   qi::rule<ForwardIterator, std::string()> content_;
};
 
 
template <class ForwardIterator, class Container, class Logger = detail::default_logger>
bool bibtex_parse(ForwardIterator begin,
                 ForwardIterator end,
                 Container & container,
                 const Logger & logger = detail::default_logger())
{
   auto skipper = sw::space | '%' >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi);
 
   bibtex_parser<ForwardIterator, decltype(skipper)> parser(logger);
 
   return qi::phrase_parse(begin, end, *parser, skipper, container) && (begin == end);
}
 
} /* namespace core */
 
} /* namespace bibmake */
 
#endif // BIBTEX_PARSER_H
 

Т.е. сейчас есть некая defaul реализация логгера, которая выводи информацию о проблеме.
Как я понимаю, то поведение, которое я добиваюсь - это вместо qi::on_error<qi::fail> поставить qi::on_error<qi::retry>, но тогда в пользовательском логгере придётся смещать указатель после того проблемного места? Ну например итерировать его на следующею позицию..

Это нормально? Или есть другие альтернативы?

Да, пользоватьльский логгер имеет следующую семантику:
Код
C++ (Qt)
struct default_logger
{
   template <class Iterator, class String>
   void operator()(const String & what, Iterator /*it_1*/, Iterator it_2, Iterator it_3) const
   {
       std::cerr   << "Error! Expecting "
                   << what
                   << " here: \""
                   << std::string(it_2, it_3)
                   << "\""
                   << std::endl;
   }
};
 

где it_1 - итератор в то место, где начался разбор данного правила с соответствующим обработчиком.
it_2 - итератор в то место, где конкретно произошла ошибка.
it_3 - конец входной строки.
what - что вызвало ошибку: строка, представляющая описание произошедшей ошибки.

Т.е. как правильно организовать вывод в лог и дальнейшее "проскальзывание" проблемных мест (с занесением их в лог)т?

 


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Май 04, 2014, 08:53
Т.е. как правильно организовать вывод в лог и дальнейшее "проскальзывание" проблемных мест (с занесением их в лог)т?
Я никогда не использовал лог. У меня всегда было, что при ошибке дальнейший разбор не имеет смысла.
Если можно, выложите или отправьте мне в личку архив с кодом, что бы можно было по разбираться. В данном случае я бы пытался перезапускать главное правило с начала. Оно рассчитывает на мусор перед entry. А вот как это сделать еще не представляю. :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: Old от Май 04, 2014, 09:09
Еще подумалось.
Вы устанавливаете обработку ошибки на правило start, можно попробовать выделить правило entry и ставить обработчик ошибки на него с retry.


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Май 04, 2014, 09:33
Цитировать
Вы устанавливаете обработку ошибки на правило start, можно попробовать выделить правило entry и ставить обработчик ошибки на него с retry.
С retry, как я понял, нужно руками двигать итератор, на то место с которого будет следующая попытка..
Это можно сделать, например в логгере..

Выкладываю минимальный проект, который воспроизводит проблему.  Файл bibliography.bib имеет 4 записи, причём во второй записи сделана ошибка (пропущена запятая)
Код
Bash
@article{Khusainov_JETPLett_2009,
 year={2009},
 issn={0021-3640},
 journal={JETP Letters},
 volume={90},
 number={5},
 doi={10.1134/S002136400917010X},
 title={Separate re-entrant superconductivity in asymmetric ferromagnet/superconductor/ferromagnet trilayers},
 url={http://dx.doi.org/10.1134/S002136400917010X},
 publisher={SP MAIK Nauka/Interperiodica},
 keywords={74.50.+r; 74.62.-c},
 author={Khusainov, M.G. and Khusainov, M.M. and Ivanov, N.M. and Proshin, Yu.N.},
 pages={359--364} <<<--------- здесь должна быть запятая
 language={English}
}
 

Первая запись парситься успешно, вторая вываливается (с логом), и на этом всё заканчивается(
А хотелось бы, чтобы  записи, которые идут после второй (неправильной) также были распарсены..)

 
Возможно, retry как раз то, что нужно..  :)


Название: Re: Хотите ли Вы в этом разбираться?
Отправлено: m_ax от Май 04, 2014, 11:18
Кажется получилось)

Сделал с retry:
Код
C++ (Qt)
qi::on_error<qi::retry>(start_, logger_wrapper(_4, _1, _3, _2));
 
а в самом  logger_wrapper после вызова пользовательского логгера перемещаю начальный указатель на то место, где возникла проблема:
Код
C++ (Qt)
void operator()(const String & what,
                   Iterator & it_1,
                   Iterator it_2,
                   Iterator it_3) const
   {
       _logger(what, it_1, it_2, it_3);
       it_1 = it_2;
   }