2012-09-09 4 views
3

문자열 규칙 쌍의 맵이 있는데 어떻게 든 "조인트 규칙"(rule_t joint_rule;)을 만들고 싶습니다.부스트 스피릿 규칙 - 규칙 연결

for (it = convert_logformat.begin(); it != convert_logformat.end(); it++) 
{ 
    joint_rule = joint_rule.copy() >> (*it).second.copy(); 
} 

그것은 수행하십시오 parse_phrase와 공동 규칙은 내가 공동 규칙이 방법을 만드는 경우

std::string entry = "127.0.0.1 [16/Aug/2012:01:50:02 +0000]"; 

는 그러나 문자열과 일치하는보다

joint_rule = convert_logformat["%h"] >> convert_logformat["%t"]; 

:이 이런 식으로 할 경우 동일한 문자열과 일치하지 않습니다. 왜? 후자와 비슷한 것을 어떻게 얻을 수 있습니까?


관련 코드 :

template <typename Iterator> 
bool parse_logentry(Iterator first, Iterator last, std::vector<char>& ip, std::vector<char>& timestamp, std::vector<char>& req, unsigned int& status, unsigned int& transferred_bytes, std::vector<char>& referer, std::vector<char>& ua) 
{ 
    using boost::spirit::qi::char_; 
    using boost::spirit::qi::int_; 
    using boost::spirit::qi::uint_; 
    using boost::spirit::qi::phrase_parse; 
    using boost::spirit::ascii::space; 
    using boost::spirit::ascii::space_type; 
    using boost::phoenix::ref; 
    using boost::phoenix::push_back; 
    using boost::spirit::qi::_1; 
    using boost::spirit::qi::lexeme; 
    using boost::spirit::qi::rule; 

    typedef boost::spirit::qi::rule<Iterator, std::string(), space_type> rule_t; 
    rule_t ip_rule, timestamp_rule, user_rule, req_rule, ref_rule, ua_rule, bytes_rule, status_rule; 
    ip_rule %= lexeme[(+char_("0-9."))[ref(ip) = _1]]; 
    timestamp_rule %= lexeme[('[' >> +(~char_(']')) >> ']')[ref(timestamp) = _1]]; 
    user_rule %= lexeme[(+~char_(" "))]; 
    req_rule %= lexeme[('"' >> +(~char_('"')) >> '"')[ref(req) = _1]]; 
    ref_rule %= lexeme[('"' >> +(~char_('"')) >> '"')[ref(referer) = _1]]; 
    ua_rule %= lexeme[('"' >> +(~char_('"')) >> '"')[ref(ua) = _1]]; 
    bytes_rule %= uint_[ref(transferred_bytes) = _1]; 
    status_rule %= uint_[ref(status) = _1]; 
    std::map<std::string, rule_t> convert_logformat; 
    typename std::map<std::string, rule_t>::iterator it; 

    convert_logformat.insert(std::pair<std::string, rule_t>("%h", ip_rule)); 
    convert_logformat.insert(std::pair<std::string, rule_t>("%t", timestamp_rule)); 
    //convert_logformat.insert(std::pair<std::string, rule_t>("%r", req_rule)); 
    //convert_logformat.insert(std::pair<std::string, rule_t>("%>s", status_rule)); 
    //convert_logformat.insert(std::pair<std::string, rule_t>("%b", bytes_rule)); 
    //convert_logformat.insert(std::pair<std::string, rule_t>("%u", user_rule)); 
    //convert_logformat.insert(std::pair<std::string, rule_t>("%{User-agent}i", ua_rule)); 
    //convert_logformat.insert(std::pair<std::string, rule_t>("%{Referer}i", ref_rule)); 

    rule_t joint_rule; 

    //joint_rule = convert_logformat["%h"] >> convert_logformat["%t"]; 

    for (it = convert_logformat.begin(); it != convert_logformat.end(); it++) 
    { 
     joint_rule = joint_rule.copy() >> (*it).second.copy(); 
     std::cout << (*it).first << ": " << typeid((*it).second).name() << "\n"; 
    } 

    std::cout << "convert_logformath: " << typeid(convert_logformat["%h"]).name() << "\n"; 

    bool r = phrase_parse(first, last, joint_rule, space); 
    if (first != last) 
     return false; 
    return r; 
} 
+0

rule_t 란 무엇입니까? SSCCE가 있습니까? http://meta.stackexchange.com/questions/22754/sscce-how-to-provide-examples-for-programming-questions/22762#22762 – sehe

+0

typedef boost :: spirit :: qi :: rule rule_t; – bayerb

+0

http://pastebin.com/uT59AMQp – bayerb

답변

3

에헴. 정말 간단합니다. 당신은

rule_t joint_rule = qi::eps; 

rule_t joint_rule; // what is it initialized to? 

for (auto it = convert_logformat.begin(); it != convert_logformat.end(); it++) 
{ 
    joint_rule = joint_rule.copy() >> (*it).second.copy(); 
} 

변경합니다 : 첫 번째 줄을 당신의 변수를 초기화해야한다 그리고 그것은 작동합니다

[email protected]:/tmp$ ./test 
127.0.0.1 
16/Aug/2012:01:50:02 +0000 

귀하의 파서는 어떤 (좋은) 일반적인 관행이 부족하다. 정돈 된 소스 (C++ 11)에 대해서는 아래를 참조하십시오. 맵의 반복 키가 아닌 삽입 순서에 의해 주문 것이기 때문에 map를 사용하여 규칙을 저장하는 것을

주, 이상한 보인다.

코드가 http://liveworkspace.org/code/a7f2f94840d63fce43d8c3f56236330e

무엇보다도,이 설정은 단순히 시작에 BOOST_SPIRIT_DEBUG을 정의하여 문법의 디버깅을 활성화 할 수 있다는
// #define BOOST_SPIRIT_DEBUG 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <typeinfo> 

namespace qi = boost::spirit::qi; 
namespace phx = boost::phoenix; 

template <typename Iterator> 
struct Grammar : qi::grammar<Iterator, std::string(), qi::space_type> 
{ 
    Grammar() : Grammar::base_type(joint_rule) 
    { 
     using namespace qi; 
     ip_rule  %= lexeme[ (+char_("0-9."))[phx::ref(ip)      = _1] ]; 
     timestamp_rule %= lexeme[ ('[' >> +(~char_(']')) >> ']')[phx::ref(timestamp) = _1] ]; 
     user_rule  %= lexeme[ (+~char_(" "))        ]; 
     req_rule  %= lexeme[ ('"' >> +(~char_('"')) >> '"')[phx::ref(req)  = _1] ]; 
     ref_rule  %= lexeme[ ('"' >> +(~char_('"')) >> '"')[phx::ref(referer) = _1] ]; 
     ua_rule  %= lexeme[ ('"' >> +(~char_('"')) >> '"')[phx::ref(ua)  = _1] ]; 
     bytes_rule  %= uint_[phx::ref(transferred_bytes)       = _1 ]; 
     status_rule %= uint_[phx::ref(status)          = _1 ]; 

     auto convert_logformat = std::map<std::string, rule_t> { 
      { "%h"   , ip_rule }  , 
      { "%t"   , timestamp_rule }, 
     // { "%r"   , req_rule }  , 
     // { "%>s"   , status_rule } , 
     // { "%b"   , bytes_rule } , 
     // { "%u"   , user_rule }  , 
     // { "%{User-agent}i", ua_rule }  , 
     // { "%{Referer}i" , ref_rule } 
     }; 

     joint_rule = eps; 

     for (auto const& p: convert_logformat) 
     { 
      joint_rule = joint_rule.copy() >> p.second.copy(); 
     } 

     BOOST_SPIRIT_DEBUG_NODE(ip_rule); 
     BOOST_SPIRIT_DEBUG_NODE(timestamp_rule); 
     BOOST_SPIRIT_DEBUG_NODE(user_rule); 
     BOOST_SPIRIT_DEBUG_NODE(req_rule); 
     BOOST_SPIRIT_DEBUG_NODE(ref_rule); 
     BOOST_SPIRIT_DEBUG_NODE(ua_rule); 
     BOOST_SPIRIT_DEBUG_NODE(bytes_rule); 
     BOOST_SPIRIT_DEBUG_NODE(status_rule); 
    } 

    typedef qi::rule<Iterator, std::string(), qi::space_type> rule_t; 
    rule_t ip_rule, timestamp_rule, user_rule, req_rule, ref_rule, ua_rule, bytes_rule, status_rule; 
    rule_t joint_rule; 

    std::vector<char> ip; 
    std::vector<char> timestamp; 
    std::vector<char> req; 
    unsigned int status; 
    unsigned int transferred_bytes; 
    std::vector<char> referer; 
    std::vector<char> ua; 
}; 

template <typename Iterator> 
bool parse_logentry(Iterator first, Iterator last, 
     Grammar<Iterator>& parser) 
{ 
    bool r = phrase_parse(first, last, parser, qi::space); 

    return (r && (first == last)); 
} 

int main(void) 
{ 
    std::string entry = "127.0.0.1 [16/Aug/2012:01:50:02 +0000]"; 
    //std::string entry = "127.0.0.1 [16/Aug/2012:01:50:02 +0000] \"GET /check.htm HTTP/1.1\" 200 17 \"-\" \"AgentName/0.1 libwww-perl/5.833\""; 

    Grammar<std::string::iterator> parser; 

    if (parse_logentry(entry.begin(), entry.end(), parser)) 
    { 
     for (auto i : parser.ip) 
      std::cout << i; 
     std::cout << "\n"; 

     for (auto ts: parser.timestamp) 
      std::cout << ts; 
     std::cout << "\n"; 
    } 
    else 
    { 
     std::cout << "not ok\n"; 
    } 

    return 0; 
} 

주에 살고 참조하십시오.

+0

와우! 감사! 불행히도 내 환경에서 컴파일러를 C++ 11 지원과 함께 사용할 수는 없지만 다른 제안은 많은 도움이됩니다. – bayerb