【问题标题】:Boost spirit grammar rule to extract just alphanumeric tokens提升精神语法规则以仅提取字母数字标记
【发布时间】:2013-05-28 21:46:22
【问题描述】:

对于字母数字的单词,我有一个如下的词素。

属性 = lexeme[+(boost::spirit::qi::alpha|boost::spirit::qi::digit)];

我想要一个语法规则,它会跳过不适合此规则的任何其他字符,并将这些字符放入向量中。

例如:输入:STR1 + STR2 % STR3 () STR4 = STR5+ STR6

           output: (STR1, STR2, STR3, STR4, STR6)

我尝试了以下语法,但在解析字符串中的第一个单词后它会跳过所有内容。如何更改它以按照我的描述进行解析?

typedef std::vector<std::wstring> Attributes;
template <typename It, typename Skipper=boost::spirit::qi::space_type>
struct AttributeParser : boost::spirit::qi::grammar<It, Attributes(),  Skipper>
{
    AttributeParser() : AttributeParser::base_type(expression)
    {
        expression = 

            *( attributes [phx::push_back(qi::_val, qi::_1)])
            >> qi::omit[*qi:char_]
            ;

        attributes = qi::lexeme[+(boost::spirit::qi::alpha|qi::boost::spirit::qi::digit)];

        BOOST_SPIRIT_DEBUG_NODE(expression);
        BOOST_SPIRIT_DEBUG_NODE(attributes);
    }


private:
    boost::spirit::qi::rule<It, std::wstring() , Skipper> attributes;
    boost::spirit::qi::rule<It, Attributes() , Skipper> expression;

};

【问题讨论】:

    标签: c++ boost boost-spirit-qi


    【解决方案1】:

    我会写下你描述的内容:

        std::vector<std::wstring> parsed;
        bool ok = qi::phrase_parse(
                begin(input), end(input),
                *qi::lexeme [ +qi::alnum ],
                ~qi::alnum,
                parsed);
    

    即:

    • 解析(部分)输入
    • 解析字母数字的词位
    • 跳过任何非字母数字
    • 将结果放入parsed向量中

    这是完整的程序

    #include <boost/spirit/include/qi.hpp>
    
    namespace qi = boost::spirit::qi;
    
    int main()
    {
        std::wstring input = L"STR1 + STR2 % STR3 () STR4 = STR5+ STR6";
    
        std::vector<std::wstring> parsed;
        bool ok = qi::phrase_parse(begin(input), end(input),
                *qi::lexeme [ +qi::alnum ],
                ~qi::alnum,
                parsed);
    
        for(auto& v : parsed)
            std::wcout << v << std::endl;
    }
    

    打印出来的

    STR1
    STR2
    STR3
    STR4
    STR5
    STR6
    

    【讨论】:

      【解决方案2】:

      在这里,您正在解析第一个字符串并将其推入向量中:

      *( attributes [phx::push_back(qi::_val, qi::_1)])
      

      接下来您将省略任何可以转换为 char 的内容:

      >> qi::omit[*qi:char_]
      

      因此,您基本上是在告诉解析器跳过字符串的其余部分,而不管字符是否为字母数字。如果你想让它工作,你需要改变

      qi::omit[*qi::char_] 
      

      类似

      qi::omit[*(qi::char_ - qi::alnum)]. 
      

      并且应该省略除字母数字之外的任何字符,它应该是您要保留的下一个字符串的开始。我现在无法尝试代码,但你明白了。

      【讨论】:

        【解决方案3】:

        除非您致力于使用 Spirit(例如,这只是在其他情况下大量使用 Spirit 的一小部分),否则我会使用自定义 ctype facet 来代替。

        struct alpha_num: std::ctype<char> {
            alpha_num(): std::ctype<char>(get_table()) {}
        
            static std::ctype_base::mask const* get_table() {
                // As far as we care, everything is white-space:
                static std::vector<std::ctype_base::mask> 
                    rc(std::ctype<char>::table_size,std::ctype_base::space);
        
                // except digits and letters:
                std::fill(&rc['0'], &rc['9'], std::ctype_base::digit);
                std::fill(&rc['a'], &rc['z'], std::ctype_base::alpha);
                std::fill(&rc['A'], &rc['Z'], std::ctype_base::alpha);
                return &rc[0];
            }
        };
        

        从那里开始,打开文件、使用该 ctype 方面为其注入区域设置并读取标记是一件相当简单的事情。这是对您输入的快速测试:

        int main() { 
        
            std::istringstream infile("STR1 + STR2 % STR3 () STR4 = STR5+ STR6");
            infile.imbue(std::locale(std::locale(), new alpha_num));
        
            // Initialize vector from file:
            std::vector<std::string> tokens((std::istream_iterator<std::string>(infile)),
                                             std::istream_iterator<std::string>());
        
            // show the tokens:
            for (auto const & s : tokens)
                std::cout << s << "\n";
            return 0;
        }
        

        结果:

        STR1
        STR2
        STR3
        STR4
        STR5
        STR6
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-05
          相关资源
          最近更新 更多