如何使用 C++ 解析 json 数组?

Posted

技术标签:

【中文标题】如何使用 C++ 解析 json 数组?【英文标题】:How can i parse json arrays with C++? 【发布时间】:2015-11-01 04:00:18 【问题描述】:
std::stringstream ss;
ss << " \"values\": \"A\": 1, \"B\": 10 ";

我想把这个流变成下面这个格式。


  "values": [
     "A": 1, "B": 10 
    ...
  ]

有人知道如何使用 c++ 解析数组的值并提升 ptree 吗?

【问题讨论】:

你试过什么?例如,您是否尝试拨打read_json?如果是这样,出了什么问题?如果没有,为什么不呢? 显示您的问题的 SSCCE 在哪里?现在:***.com/search?q=user%3A85371+JSON+array+ 这已被多次询问,并在 JSON 解析器的约 20 行文档中进行了描述 阅读文档。 【参考方案1】:

假设输入input.json

使用 Boost Spirit V2.x

这是一个使用增强精神气的简单方法:

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_match.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <fstream>
#include <map>

namespace 
    using Element = std::map<std::string, int>;
    struct Array : std::vector<Element>  ;

    std::istream& operator>>(std::istream& is, Array& into) 
        using namespace boost::spirit::qi;
        using it = boost::spirit::istream_iterator;

        rule<it, std::string()> s;
        rule<it, Element(), space_type> r, e;

        s = '"' >> ~char_('"') >> '"';
        r = (s >> ':' >> int_) % ',';
        e = '' >> r >> '';

        return is >> phrase_match(''
                    >> lit("\"values\"") >> ':' >> '[' >> (e % ',') >> ']'
                >> '', space, into);
    


int main() 
    std::ifstream ifs("input.json");
    ifs.unsetf(std::ios::skipws);

    Array array;
    if (ifs >> array) 
        std::cout << "Parsed " << array.size() << " elements:\n";

        for (auto& e : array) 
            std::cout << "\n--------------------\n ";
            for (auto& kv : e)
                std::cout << "\"" << kv.first << "\": " << kv.second << ", ";
            std::cout << " \n";
        
     else 
        std::cout << "Parsing failed\n";
    

打印

std::istream& anonymous::operator>>(std::istream&, anonymous::Array&)
Parsed 13 elements:
--------------------
 "A": 1, "B": 10,  
--------------------
 "C": 3, "D": 12,  
--------------------
 "E": 5, "F": 14,  
--------------------
 "G": 7, "H": 16,  
--------------------
 "I": 9, "J": 18,  
--------------------
 "K": 11, "L": 20,  
--------------------
 "M": 13, "N": 22,  
--------------------
 "O": 15, "P": 24,  
--------------------
 "Q": 17, "R": 26,  
--------------------
 "S": 19, "T": 28,  
--------------------
 "U": 21, "V": 30,  
--------------------
 "W": 23, "X": 32,  
--------------------
 "Y": 25, "Z": 34,  

使用 Spirit X3

同样的交易:

Live On Coliru

namespace 
    using Element = std::map<std::string, int>;
    struct Array : std::vector<Element>  ;

    namespace parser 
        using namespace boost::spirit::x3;
        rule<struct rule_key_t, std::string> s;
        rule<struct rule_element_t, Element> r;
        rule<struct rule_braced_t, Element>  e;

        auto s_def = '"' >> ~char_('"') >> '"';
        auto r_def = (s >> ':' >> int_) % ',';
        auto e_def = '' >> r >> '';

        BOOST_SPIRIT_DEFINE(s,r,e)
    

    std::istream& operator>>(std::istream& is, Array& into) 
        using namespace parser;

        boost::spirit::istream_iterator f(is), l;

        if (!phrase_parse(f, l, ''
                    >> lit("\"values\"") >> ':' >> '[' >> (e % ',') >> ']'
                >> '', space, into))
        
            is.setstate(is.rdstate() | std::ios::failbit);
        

        return is;
    

同样的输出和同样的main()

使用属性树

这有点不同,我选择不实现operator&gt;&gt;,因为 Boost Property 并没有真正负担得起。

Live On Coliru

#include <boost/property_tree/json_parser.hpp>
#include <fstream>
#include <iostream>
#include <map>

namespace 
    using Element = std::map<std::string, int>;
    struct Array : std::vector<Element>  ;

    Array read(std::string fname) 
        std::ifstream ifs(fname);
        Array into;

        using namespace boost::property_tree;
        ptree pt;
        read_json(ifs, pt);

        for (auto& entry : pt.get_child("values")) 
            Element e;
            for (auto& property : entry.second)
                e[property.first] = property.second.get_value(0);
            into.push_back(std::move(e));
        

        return into;
    


int main() 
    try 
        auto array = read("input.json");
        std::cout << "Parsed " << array.size() << " elements:\n";

        for (auto& e : array) 
            std::cout << "--------------------\n ";
            for (auto& kv : e)
                std::cout << "\"" << kv.first << "\": " << kv.second << ", ";
            std::cout << " \n";
        
     catch (...) 
        std::cout << "Parsing failed\n";
    

当然,输出还是和之前一样。

【讨论】:

而且我已经完成了 3 个竞争性实施,以过度杀戮的古老传统:live coding session (experiment) 我不想学习@Columbo 说真的,继续努力,很棒的东西! Boost 很强大...非常强大。用你的几行代码,我解决了几个小时的问题......谢谢。【参考方案2】:

使用 ThorsSerizlier 和与 sehe 相同的输入。

假设输入input.json

#include "ThorSerialize/JsonThor.h"
#include "ThorSerialize/SerUtil.h"
#include "ThorSerialize/Traits.h"
#include <iostream>
#include <fstream>

struct Data

    std::vector<std::map<std::string, int>>     values; // The values input
;
ThorsAnvil_MakeTrait(Data, values);  // Describes what can be serialized
                                     // There is a definition for all standard
                                     // types in SerUtil.h

int main()

    std::ifstream   dataStream("input.json");
    Data            data;

    // Automatically reads data into C++ structure.
    // Directly from a stream.
    dataStream >> ThorsAnvil::Serialize::jsonImport(data);

    // Converts a C++ structure into JSON for output to  a stream.
    std::cout << ThorsAnvil::Serialize::jsonExport(data);

【讨论】:

以上是关于如何使用 C++ 解析 json 数组?的主要内容,如果未能解决你的问题,请参考以下文章

C++ json解析

C++下如何将json数据存入mysql数据库

如何使用php解析json数组并显示?

Qt 并在 C++ 中解析 JSON 数据 [关闭]

如何使用 Gson 解析 JSON 数组

如何使用 javascript 解析带有数组的外部 JSON 文件