栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

使用C ++和BOOST读取JSON文件

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用C ++和BOOST读取JSON文件

由于另一个答案中的数据结构被认为“非常复杂”,因此建议目标数据结构为:

struct Data {    struct Folder { int id, parent_id; std::string path; };    struct File   { int id, parent_id; std::string path, name, md5_hash; };    using Folders = std::vector<Folder>;    using Files   = std::vector<File>;    Folders folders;    Files   files;};

但是,如果我们“跳过中间人”并将JSON专门解析为所示

Data
结构,则OP可能会更满意。这“简化”了语法,使其仅针对此类文档:

start    = '{' >> (folders_ >> commasep) ^(files_ >> commasep)         >> '}';folders_ = prop_key(+"folders") >> '[' >> -(folder_ % ',') >> ']';files_   = prop_key(+"files")   >> '[' >> -(file_   % ',') >> ']';folder_  = '{' >> (     (prop_key(+"id")        >> int_  >> commasep) ^     (prop_key(+"parent_id") >> int_  >> commasep) ^     (prop_key(+"path")      >> text_ >> commasep) ) >> '}';file_    = '{' >> (     (prop_key(+"id")        >> int_  >> commasep) ^     (prop_key(+"parent_id") >> int_  >> commasep) ^     (prop_key(+"path")      >> text_ >> commasep) ^     (prop_key(+"name")      >> text_ >> commasep) ^     (prop_key(+"hash")      >> text_ >> commasep) ) >> '}';prop_key = lexeme ['"' >> lazy(_r1) >> '"'] >> ':';commasep = &char_('}') | ',';

这个语法允许

  • 无关紧要的空格,
  • 对象内属性的重新排序
  • 和省略的对象属性

优点:

  • 及早检查属性值类型
  • 缩短编译时间
  • 确实减少了代码: 减少了37个LoC (不计算样本JSON行的〜22%)

最后一个好处是反面:如果您想读取稍有不同的JSON,现在您需要处理语法,而不仅仅是编写其他提取/转换。
在37行代码中,我偏爱其他答案,但我将由您自己决定。

这是直接使用此语法的相同演示程序:

[Live On Coliru](http://coliru.stacked-crooked.com/a/cbbe576146a96f58)

//#define BOOST_SPIRIT_DEBUG#include <boost/fusion/adapted.hpp>#include <boost/spirit/include/qi.hpp>#include <boost/spirit/include/phoenix.hpp>namespace qi = boost::spirit::qi;static std::string const sample = R"(    {        "folders" :        [{     "id" : 109,     "parent_id" : 110,     "path" : "/1/105/110/" }, {     "id" : 110,     "parent_id" : 105,     "path" : "/1/105/" }        ],        "files" :        [{     "id" : 26,     "parent_id" : 105,     "name" : "picture.png",     "hash" : "md5_hash",     "path" : "/1/105/" }, {     "id" : 25,     "parent_id" : 110,     "name" : "another_picture.jpg",     "hash" : "md5_hash",     "path" : "/1/105/110/" }        ]    })";struct Data {    struct Folder { int id, parent_id; std::string path; };    struct File   { int id, parent_id; std::string path, name, md5_hash; };    using Folders = std::vector<Folder>;    using Files   = std::vector<File>;    Folders folders;    Files   files;};BOOST_FUSION_ADAPT_STRUCT(data::Folder, (int,id)(int,parent_id)(std::string,path))BOOST_FUSION_ADAPT_STRUCT(data::File,   (int,id)(int,parent_id)(std::string,path)(std::string,name)(std::string,md5_hash))BOOST_FUSION_ADAPT_STRUCT(Data,         (data::Folders,folders)(data::Files,files))namespace folder_info { // adhoc JSON parser    template <typename It, typename Skipper = qi::space_type>    struct grammar : qi::grammar<It, Data(), Skipper>    {        grammar() : grammar::base_type(start) { using namespace qi; start    = '{' >>  (folders_ >> commasep) ^ (files_ >> commasep)          >> '}'; folders_ = prop_key(+"folders") >> '[' >> -(folder_ % ',') >> ']'; files_   = prop_key(+"files")   >> '[' >> -(file_   % ',') >> ']'; folder_  = '{' >> (      (prop_key(+"id")        >> int_  >> commasep) ^      (prop_key(+"parent_id") >> int_  >> commasep) ^      (prop_key(+"path")      >> text_ >> commasep)  ) >> '}'; file_    = '{' >> (      (prop_key(+"id")        >> int_  >> commasep) ^      (prop_key(+"parent_id") >> int_  >> commasep) ^      (prop_key(+"path")      >> text_ >> commasep) ^      (prop_key(+"name")      >> text_ >> commasep) ^      (prop_key(+"hash")      >> text_ >> commasep)  ) >> '}'; prop_key = lexeme ['"' >> lazy(_r1) >> '"'] >> ':'; commasep = &char_('}') | ','; //////////////////////////////////////// // Bonus: properly decoding the string: text_   = '"' >> *ch_ >> '"'; ch_ = +(         ~char_(""\")) [ _val += _1 ] | qi::lit("x5C") >> (    //  (reverse solidus) qi::lit("x22") [ _val += '"'  ] | // "    quotation mark  U+0022 qi::lit("x5C") [ _val += '\' ] | //     reverse solidus U+005C qi::lit("x2F") [ _val += '/'  ] | // /    solidus         U+002F qi::lit("x62") [ _val += 'b' ] | // b    backspace       U+0008 qi::lit("x66") [ _val += 'f' ] | // f    form feed       U+000C qi::lit("x6E") [ _val += 'n' ] | // n    line feed       U+000A qi::lit("x72") [ _val += 'r' ] | // r    carriage return U+000D qi::lit("x74") [ _val += 't' ] | // t    tab  U+0009 qi::lit("x75")         // uXXXX     U+XXXX      >> _4HEXDIG [ append_utf8(qi::_val, qi::_1) ]         ); BOOST_SPIRIT_DEBUG_NODES((files_)(folders_)(file_)(folder_)(start)(text_))        }    private:        qi::rule<It, Data(), Skipper> start;        qi::rule<It, data::Files(),     Skipper> files_;        qi::rule<It, data::Folders(),   Skipper> folders_;        qi::rule<It, data::File(),      Skipper> file_;        qi::rule<It, data::Folder(),    Skipper> folder_;        qi::rule<It, void(const char*), Skipper> prop_key;        qi::rule<It, std::string()> text_, ch_;        qi::rule<It> commasep;        struct append_utf8_f { template <typename...> struct result { typedef void type; }; template <typename String, typename Codepoint> void operator()(String& to, Codepoint prepoint) const {     auto out = std::back_inserter(to);     boost::utf8_output_iterator<decltype(out)> convert(out);     *convert++ = prepoint; }        };        boost::phoenix::function<append_utf8_f> append_utf8;        qi::uint_parser<uint32_t, 16, 4, 4> _4HEXDIG;    };    template <typename Range, typename It = typename boost::range_iterator<Range const>::type>    Data parse(Range const& input) {        grammar<It> g;        It first(boost::begin(input)), last(boost::end(input));        Data parsed;        bool ok = qi::phrase_parse(first, last, g, qi::space, parsed);        if (ok && (first == last)) return parsed;        throw std::runtime_error("Remaining unparsed: '" + std::string(first, last) + "'");    }}int main(){    auto parsed = folder_info::parse(sample);    for (auto& e : parsed.folders)         std::cout << "folder:t" << e.id << "t" << e.path << "n";    for (auto& e : parsed.files)         std::cout << "file:t"   << e.id << "t" << e.path << "t" << e.name << "n";}

输出:

folder: 109 /1/105/110/folder: 110 /1/105/file:   26  /1/105/ picture.pngfile:   25  /1/105/110/ another_picture.jpg


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/609091.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号