4

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

属性 = 词位[+(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;

};
4

3 回答 3

2

我会从字面上写下你描述的内容:

    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
于 2013-05-29T01:02:54.137 回答
1

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

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

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

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

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

qi::omit[*qi::char_] 

类似于

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

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

于 2013-05-30T00:22:36.693 回答
0

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

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 facet 为其注入语言环境并读取标记是一件相当简单的事情。这是您输入的快速测试:

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
于 2013-05-28T22:08:37.970 回答