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;}
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;}
Bashm_ax: parsing time, (ms) = 26number of entries = 126 old: parsing time, (ms) = 9number of entries = 126 igors: parsing time, (ms) = 11number of entries = 123 ---------------------------------------------------------------------------m_ax: parsing time, (ms) = 22number of entries = 126 old: parsing time, (ms) = 5number of entries = 126 igors: parsing time, (ms) = 10number of entries = 123 ---------------------------------------------------------------------------m_ax: parsing time, (ms) = 20number of entries = 126 old: parsing time, (ms) = 7number of entries = 126 igors: parsing time, (ms) = 13number of entries = 123
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
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
C++ (Qt)if (!reader.ReadBibTag(theBib.back())) theBib.pop_back();
Bashm_ax: parsing time, (ms) = 18number of entries = 126 old: parsing time, (ms) = 4number of entries = 126 igors: parsing time, (ms) = 22number of entries = 123 -------------------------------------------------------------------m_ax: parsing time, (ms) = 20number of entries = 126 old: parsing time, (ms) = 12number of entries = 126 igors: parsing time, (ms) = 16number of entries = 123 -------------------------------------------------------------------m_ax: parsing time, (ms) = 18number of entries = 126 old: parsing time, (ms) = 9number of entries = 126 igors: parsing time, (ms) = 21number of entries = 123
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;};
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;};