【问题标题】:Attributes of sequence and list operator in boost.spirit qi?boost.spirit qi中序列和列表运算符的属性?
【发布时间】:2019-10-12 11:43:21
【问题描述】:

我想解析类似的东西

"{xxxx}
{xxxx}"

由 eol 分隔成 vector<vector<wchar_t>> : ({xxxx},{xxxx}) 以便“{”和“}”与内部字符保持在一起。 我的代码是:

#define BOOST_SPIRIT_UNICODE

#include <iostream>
#include<boost/spirit/include/qi.hpp>
#include<string>
#include<vector>

using namespace std;
namespace sw=boost::spirit::standard_wide;
namespace qi= boost::spirit::qi;
using boost::spirit::standard_wide::char_;

int main()
{
    wstring s = L"{\"id\":23,\"text\":\"sf\nsf\"}\n{\"id\":23,\"text\":\"sfsf\"}";
    qi::rule<wstring::iterator, vector<vector<wchar_t>>(), sw::blank_type> ru;
    ru = (qi::char_(L"{") >> *(char_-char_(L"}")) >> char_(L"}")) % qi::eol;
    vector<vector<wchar_t>> result;
    qi::phrase_parse(s.begin(), s.end(), ru, sw::blank, result);

    for (auto& v : result) {
        //cout << "Size of string: " << v.size() << endl;
        for (auto& s : v) {
            wcout << s;
        };
        cout << endl;
    };
    std::cout << "Size of result"<<result.size()<<endl ;
}

但是输出是:

{
"id":23,"text":"sf
sf"
}
{
"id":23,"text":"sfsf"
}
Size of result6

看起来“{”变成了外部向量的 vector&lt;wchar_t&gt; 类型的单个元素。

然后考虑规则:

ru = (qi::char_(L"{") >> *(char_-char_(L"}")) >> char_(L"}")) % qi::eol;

根据文档,*(char_-char_(L"}")) 应该是vector&lt;A&gt;。因为a: A, b: vector&lt;A&gt; --&gt; (a &gt;&gt; b): vector&lt;A&gt;,那么我认为(qi::char_(L"{") &gt;&gt; *(char_-char_(L"}")) &gt;&gt; char_(L"}"))应该是vector&lt;wchar_t&gt;。这与结果相矛盾。

我哪里错了?

【问题讨论】:

    标签: c++ boost-spirit-qi


    【解决方案1】:

    又因为a: A, b: vector --> (a >> b): vector,那我认为(qi::char_(L"{") >> *(char_-char_(L"} ")) >> char_(L"}")) 应该是向量。这与结果相矛盾。

    确实不是这样。应用来自 Detecting the parameter types in a Spirit semantic action 的现代化技巧

    struct sense_f {
        template <typename T> void operator()(T&&) const {
            std::cout << boost::core::demangle(typeid(T).name()) << "\n";
        }
    };
    static const boost::phoenix::function<sense_f> sense;
    

    我们可以打印出实际的属性类型:

    ru = (char_(L'{') >> *(char_ - char_(L'}')) >> char_(L'}')) [sense(qi::_0)] % qi::eol;
    

    将打印 Live On Coliru

    boost::fusion::vector<wchar_t, std::vector<wchar_t, std::allocator<wchar_t> >, wchar_t>
    

    简单的解决方案

    假设您不需要捕获 {},您可以将它们设为文字而不是 char_

    ru = (L'{' >> *(char_ - L'}') >> L'}') [sense(qi::_0)] % qi::eol;
    

    将打印 Live On Coliru

    boost::fusion::vector<std::vector<wchar_t, std::allocator<wchar_t> >&>
    

    确实,如果你也让它传播属性:

    ru %= (L'{' >> *(char_ - L'}') >> L'}') [sense(qi::_0)] % qi::eol;
    

    程序打印:

    boost::fusion::vector<std::vector<wchar_t, std::allocator<wchar_t> >&>
    boost::fusion::vector<std::vector<wchar_t, std::allocator<wchar_t> >&>
    "\"id\":23,\"text\":\"sf
    sf\""
    "\"id\":23,\"text\":\"sfsf\""
    

    注意std::vector&lt;wchar_t&gt;std::wstring 之间存在属性兼容性,这就是我使用后者的原因。

    奖金

    如果您确实想要包含 {} 和任何中间空格,请使用 qi::raw

    ru %= qi::raw [L'{' >> *(char_ - L'}') >> L'}'] [sense(qi::_0)] % qi::eol;
    

    现在打印出来了:

    boost::fusion::vector<boost::iterator_range<__gnu_cxx::__normal_iterator<wchar_t const*, std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > > >&>
    boost::fusion::vector<boost::iterator_range<__gnu_cxx::__normal_iterator<wchar_t const*, std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > > >&>
    "{\"id\":23,\"text\":\"sf
    sf\"}"
    "{\"id\":23,\"text\":\"sfsf\"}"
    

    正如您所见,即使iterator_range&lt;It&gt; 也与std::wstring 具有属性兼容性,因为输入也是wchar_t 的序列。

    当然,除非您想要该输出,否则请关闭 sense 操作。

    完整列表

    使用qi::raw方法的最终结果:

    Live On Coliru

    #define BOOST_SPIRIT_UNICODE
    
    #include <boost/spirit/include/qi.hpp>
    #include <iostream>
    #include <iomanip>
    #include <string>
    #include <vector>
    
    namespace sw = boost::spirit::standard_wide;
    namespace qi = boost::spirit::qi;
    using sw::char_;
    
    int main() {
        std::wstring s = LR"({"id":23,"text":"sf
    sf"}
    {"id":23,"text":"sfsf"})";
    
        using Data = std::vector<std::wstring>;
        using It = std::wstring::const_iterator;
    
        qi::rule<It, Data(), sw::blank_type> ru
            = qi::raw [L'{' >> *(char_ - L'}') >> L'}'] % qi::eol;
    
        Data result;
        It f = s.begin(), l = s.end();
    
        if (qi::phrase_parse(f, l, ru, sw::blank, result)) {
            for (auto& s : result) {
                std::wcout << std::quoted(s) << std::endl;
            };
        } else {
            std::wcout << "Parse failed\n";
        }
    
        if (f!=l) {
            std::wcout << L"Remaining unparsed: " << std::quoted(std::wstring(f,l)) << std::endl;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-22
      • 2016-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多