c++:解析JSON字符串,关键字不包含在双引号中

C++: parsing JSON string, having keys not enclosed into double quotes

本文关键字:包含 关键字 解析 JSON 字符串 c++      更新时间:2023-10-16

我已经成功使用卡萨布兰卡Json c++库(cppresst)一段时间了。它的解析器(web::json::value::parse(<json_string>))可以完美地处理有效的 JSON字符串。说这将被正确解析:

{
  "key1": [["1", 0.4], ["0", 0.6]],
  "key2": true,
  "key3": 1,
  "key4": [{"key41": 1}, {"key42": [1,2,3]}]
}    

现在,我面临解析JSON对象的必要性,其关键字没有被括在双引号中:

{
  key1: [[1, 0.4], [0, 0.6]],
  key2: true,
  key3: 1,
  key4: [{key41: 1}, {key42: [1,2,3]}]
}

是否有一个很好的方法来正确解析这个,然后序列化成一个有效的JSON,这样卡萨布兰卡可以正确解析结果的有效JSON ?

Hjson似乎可以用于此目的,但它不提供c++所需的库。他们提到了C语言的jzon库——我试过了:它只有单向解析(没有序列化),甚至解析也不能正确工作(甚至不能解析有效的json)

这可能不是最快的方法,但是如果用最少的代码行数来衡量代码的优美程度,那么它将会非常高。

你得到的是一个类似javascript的对象。让我们将其插入javascript引擎并使用它来生成适当的JSON。我将使用Qt的QJSEngine,因为我对它相当熟悉:

constexpr char const* str = R"({
    key1: [[1, 0.4], [0, 0.6]],
    key2: true,
    key3: 1,
    key4: [{key41: 1}, {key42: [1,2,3]}]
})";
QJSEngine e;
QString script = QString("JSON.stringify(%0)").arg(str);

就可以求值了

e.evaluate(script).toString().toStdString()
收益率

{"key1":[[1,0.4],[0,0.6]],"key2":true,"key3":1,"key4":[{"key41":1},{"key42":[1,2,3]}]}

这个粗糙的方法可以工作。

(未测试代码)

我们有三个状态,NEUTRAL, ONSTRING和ONALNUM。

我们从中性开始。如果我们点击"我们进入ONSTRING。如果我们点击alpha,我们进入ONALNUM。如果我们进入或离开校友,我们发出一个引号。我们还发出字符read。如果我们在ONALNUM中,当我们点击非alnum时,我们将退出它,并进入NEUTRAL,除非我们点击quote,当它是一个解析错误时。如果我们在ONSTRING中,我们应用JSON字符串转义规则,我不知道。

 #define NEUTRAL 0
 #define ONSTRING 1
 #define ONALNUM 2
 int state = NEUTRAL;
 char *inptr = str;
 char ch;
 while( (ch = *inptr++))
 {
    if(state == NEUTRAL)
    {
       if( isalpha(ch) )
       {
           emit('"');
           state = ONALNUM;
       }
       else if(ch = '"')
          state = ONSTRING;
       emit(ch);
    }
    else if(state == ONSTRING)
    {
        /* JSON string escape rules here */
        if(ch == '"')
          state = NEUTRAL;
        emit(ch);
    }
    else if(state == ONALNUM)
    {
       emit(ch);
       if(!isalnum(ch))
       {
          state = NEUTRAL;
          emit('"');
       }
    }
 }

问题

根据你的问题的上下文,你想要删除",这样你就可以有一个适当的JSON格式。

对于JSON解析部分,您应该使用库。我很快就会在这里发布一个例子。

解决方案

为了做到这一点,我们将使用<algorithm>库中的std::replace函数;虽然我们可以自己实现这些功能,但最好还是使用标准库,因为标准库的创建者努力优化了这些函数,使其发挥最大的功能。所以,让我们把你从问题中给我们的代码,并使其适合json。

#include <algorithm>
#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::endl;
void convert_char(string &s,char from_conv, char to_conv) {
  std::replace( s.begin(), s.end(), from_conv, to_conv); // replace all 'x' to 'y'
}
int main()
{
    string str =  "{ n 
    "key1": [["1", 0.4], ["0", 0.6]], n 
    "key2": true, n 
    "key3": 1,  n 
    "key4": [{"key41": 1}, {"key42": [1,2,3]}] n }";;
    convert_char(str,'"',(char)0);
    cout << str << endl;
}

你可以看到这里有一个叫做convert_char的函数,它将一个字符转换为另一个字符。所以基本上就像你问的那样,我们去掉了双引号,然后,它的格式就像JSON了!看一下这里的的演示。

JSON解析器解决方案

显然,这里您将使用库来为您完成此操作。我要向大家介绍sciter !基本上,对于sciter,你所要做的就是:

#include <algorithm>
#include <string>
#include <iostream>
#include <sciter>
using std::string;
using std::cout;
using std::endl;
int main()
{
    string str =  "{ n 
    "key1": [["1", 0.4], ["0", 0.6]], n 
    "key2": true, n 
    "key3": 1,  n 
    "key4": [{"key41": 1}, {"key42": [1,2,3]}] n }";;
    sciter::value str_conv = sciter::value::from_string( str, CVT_JSON_LITERAL );
    cout << str_conv << endl;
}

现在根据这段代码,JSON格式的代码是在str_conv !下面的参考资料部分提供了指导您完成此操作的参考资料。

引用:

sciter

std::replace

string::replace

std::refrence_if

词汇表

std::replace :

原型:

template <class ForwardIterator, class T>
  void replace (ForwardIterator first, ForwardIterator last,
                const T& old_value, const T& new_value); //source cpprefrence

引用:cpprefrence

<algorithm> :

许多主题都在算法库中。你猜对了,它是一个算法库。

头文件<algorithm>定义了一组特别设计用于元素范围的函数。

范围是任何可以通过迭代器或指针访问的对象序列,例如数组或某些STL容器的实例。但是请注意,algorithms通过iterators直接对值进行操作,不会以任何方式影响任何可能的容器的结构(它从不影响容器的大小或存储分配)。

算法库为各种目的(如搜索、排序、计数、操作)定义了对元素范围进行操作的函数。

引用:

cplusplus

cpprefrence