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

我只是一个虾纸丫 提交于 2019-12-12 04:31:13

问题


I've been using Casablanca Json C++ library (cpprest) successfully for some time. Its parser (web::json::value::parse(<json_string>)) works perfectly on valid JSON strings. Say this will be parsed correctly:

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

Now, I faced the necessity of parsing JSON objects, the keys of which are not enclosed into double quotes:

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

Is there a nice way to correctly parse this and then serialize into a valid JSON, so that Casablanca can parse the resultant valid JSON correctly?

Hjson seems to work for this purpose, but it doesn't provide the required library for C++. They mention jzon library for C - I tried it: it has only one-way parsing (no serialization), and even parsing doesn't work correctly (can't even parse valid JSONs)


回答1:


This probably won't be the fastest way to do this, but if niceness is measured in least lines of code, it'll come up pretty high.

What you have is a javascript-like object. Let's plug it into a javascript engine and use it to spit out proper JSON. I'll use Qt's QJSEngine since I'm passably familiar with it:

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);

then you can just evaluate it:

e.evaluate(script).toString().toStdString()

yields

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



回答2:


This crude method will work.

(Untested code )

We've got three states, NEUTRAL, ONSTRING, and ONALNUM.

We start in NEUTRAL. If we hit '"' we go into ONSTRING. If we hit alpha we go into ONALNUM. If we go into or out of alnum, we emit a quote. We also emit the character read. If we are in ONALNUM, we get out of it when we hit non-alnum, amd go into NEUTRAL, unless we hit quote, when it's a parse error. If we are in ONSTRING we apply JSON string escape rules, which I don't know offhand.

 #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('\"');
       }
    }
 }



回答3:


Problem

It seems by the context of your question that you want the "" removed so you can have a proper JSON format.

For the JSON parsing part, you should use a library. I'm going to post an example of it here, soon.

Solution

In order to do that, we are going to use the std::replace function from the <algorithm> library; although we can implement this on our own, it is better to use standard libraries since the creators of them worked hard on optimizing those function to the fullest capabilities. So let's take your code you gave us from the question and make it JSON-appropriate.

#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;
}

You can see here we have a function called convert_char which converts a certain character to another. So basically as your question asked we removed the double quotation, and tada, it is formatted like JSON! Take a look here for the demo.

Solution to JSON Parser

Obviously, here you will use a library to do this for you. I'm going to introduce sciter to you! Basically, with sciter all you got to do is:

#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;
}

Now according to this code, the JSON Formatted code is in str_conv! References to guide you through this are below in the References section.

References:

sciter

cpprefrence std::replace

string::replace

cpprefrence std::refrence_if

Glossary

std::replace :

Prototype:

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

references: cpprefrence

<algorithm>:

Many topics are inside the algorithm library. It's a library for, you guessed it, algorithms.

The header <algorithm> defines a collection of functions especially designed to be used on ranges of elements.

A range is any sequence of objects that can be accessed through iterators or pointers, such as an array or an instance of some of the STL containers. Notice though, that algorithms operate through iterators directly on the values, not affecting in any way the structure of any possible container (it never affects the size or storage allocation of the container).

The algorithms library defines functions for a variety of purposes (e.g. searching, sorting, counting, manipulating) that operate on ranges of elements.

References:

cplusplus

cpprefrence



来源:https://stackoverflow.com/questions/39928124/c-parsing-json-string-having-keys-not-enclosed-into-double-quotes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!