Search code examples
jsonc++11rapidjson

RapidJSON Convert String Value to Indexed Array?


I have a JSON string, in which value is actually a string, but I need to access it like JSON array. {"data" : "[A,B,C]"}.

Is there any way to parse VALUE as Indexed array using RapidJSON so that I get a document like: {"0" : "A", "1" : "B", "2" : "C"}


Solution

  • RapidJSON Should be fully in compliance With RFC7159 / ECMA-404.

    No there is no way, you need to do it manually.

    For example using regex:

    #include <iostream>
    #include <iterator>
    #include <string>
    #include <regex>
    
    static std::regex value_regex("[\\s]*([\\w\\s]+),?", std::regex::optimize);
    
    std::string parse(const std::string& value) {
        if (value.at(0) != '[' || value.at(value.size() - 1) != ']') {
            throw std::invalid_argument("Error in Parse [must start with '[' and end with ']']: " + value);
        }
    
        std::string result("{");
        std::sregex_iterator next(++value.begin(), --value.end(), value_regex, std::regex_constants::match_continuous);
        std::sregex_iterator end;
        size_t len = 0, cont = 0;
        while (next != end) {
            if (cont) {
                result.append(", \"").append(std::to_string(cont)).append("\":\"").append(next->str(1)).append(1, '\"');
            } else {
                result.append(1, '\"').append(std::to_string(cont)).append("\":\"").append(next->str(1)).append(1, '\"');
            }
            len += next->length(0);
            ++next;
            ++cont;
        }
    
        if (len != value.size() - 2) {
            throw std::invalid_argument("Error in Parse [" + std::to_string(len) + "]: " + value);
        }
    
        result.append(1, '}');
        return result;
    }
    
    int main() {
        // Tests
        try {
            std::string value("[A,B,C,D,E]");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::invalid_argument& err) {
            std::cout << err.what() << std::endl;
        }
        try {
            std::string value("[  A, B X, Z]");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::invalid_argument& err) {
            std::cout << err.what() << std::endl;
        }
        try {
            std::string value("[A,BaaayyX, Z]");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::invalid_argument& err) {
            std::cout << err.what() << std::endl;
        }
        try {
            std::string value("[A,B,C,]");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::invalid_argument& err) {
            std::cout << err.what() << std::endl;
        }
        try {
            std::string value("[]");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::invalid_argument& err) {
            std::cout << err.what() << std::endl;
        }
    
    
        // Errors
        try {
            std::string value("A,B,C");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::invalid_argument& err) {
            std::cout << err.what() << std::endl;
        }
    
        try {
            std::string value("A,B,C]");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::invalid_argument& err) {
            std::cout << err.what() << std::endl;
        }
    
        try {
            std::string value("[A,B,C");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::invalid_argument& err) {
            std::cout << err.what() << std::endl;
        }
    
        try {
            std::string value("[,A,B,C]");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::invalid_argument& err) {
            std::cout << err.what() << std::endl;
        }
    
        try {
            std::string value("");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::exception& err) {
            std::cout << err.what() << std::endl;
        }
    
        try {
            std::string value("[");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::exception& err) {
            std::cout << err.what() << std::endl;
        }
    
        try {
            std::string value("]");
            std::cout << value << "  ->  " << parse(value) << std::endl;
        } catch (const std::exception& err) {
            std::cout << err.what() << std::endl;
        }
    }
    

    Output:

    [A,B,C,D,E]  ->  {"0":"A", "1":"B", "2":"C", "3":"D", "4":"E"}
    [  A, B X, Z]  ->  {"0":"A", "1":"B X", "2":"Z"}
    [A,BaaayyX, Z]  ->  {"0":"A", "1":"BaaayyX", "2":"Z"}
    [A,B,C,]  ->  {"0":"A", "1":"B", "2":"C"}
    []  ->  {}
    A,B,C  ->  Error in Parse [must start with '[' and end with ']']: A,B,C
    A,B,C]  ->  Error in Parse [must start with '[' and end with ']']: A,B,C]
    [A,B,C  ->  Error in Parse [must start with '[' and end with ']']: [A,B,C
    [,A,B,C]  ->  Error in Parse [0]: [,A,B,C]
      ->  basic_string
    [  ->  Error in Parse [must start with '[' and end with ']']: [
    ]  ->  Error in Parse [must start with '[' and end with ']']: ]
    

    You can customize your regex to become more flexible or more strict.