Error in JSON string creation with / operator using jsoncpp library - c++

I am using JSONcpp library and facing problem to create json which contains / operator (like date : 02/12/2015). Below is my code:
JSONNODE *n = json_new(JSON_NODE);
json_push_back(n, json_new_a("String Node", "02/05/2015"));
json_char *jc = json_write_formatted(n);
printf("%s\n", jc);
json_free(jc);
json_delete(n);
Output :
{
"String Node":"02\/05\/2015"
}
Check here "\/" in date, we want only "/" in date, so my expected output should look like this:
Expected output:
{
"String Node":"02/05/2015"
}
How to get rid of it? We are using inbuilt library function and we can not modify library.

According to this example
The json_new_a method will escape your string values when you go to
write the final string.
The additional backslashes you are facing in the output are the result of adding escape characters. This is actually a good thing as it prevents both accidental and intentional errors.
I suppose the easies option for you would be to replace all \/ occurrences in output string with single /. I wrote a simple program to do so:
#include <iostream>
#include <string>
#include <boost/algorithm/string/replace.hpp>
using namespace std;
int main()
{
//Here's the "json_char *jc" from your code
const char* jc = "02\\/05\\/2015";
//Replacing code
string str(jc);
boost::replace_all(str, "\\/", "/");
//Show result
cout << "Old output: " << jc << endl;
cout << "New output: " << str << endl;
}
Live demo
BTW: libJSON is not really a C++ library - it's much more C-style which involves many low-level operations and is more complicated and obfuscated than more C++ish libraries. If you'd like to try, there is a nice list of C++ JSON libs here.

Related

Accessing JSON values in C++

I am trying to write a program that navigates your local disc in Unreal Engine for a small application. I have put together a REST server using Gradle, and long story short, I am given a JSON with a machines directories. I want to pull out the specific directories names, to be returned as string (FText specifically, but that not too important here) array.
I found a library created by nLohmann on github (https://github.com/nlohmann/json) which seems to be the best way to handle a JSON in c++. For the life of me, however, I can't figure out how to pull the directory names out. I've tried an iterator and a straightforward .value() call.
The code and a JSON example are below, any insight would be greatly appreciated.
char buffer[1024];
FILE *lsofFile_p = _popen("py C:\\Users\\jinx5\\CWorkspace\\sysCalls\\PullRoots.py", "r");
fgets(buffer, sizeof(buffer), lsofFile_p);
_pclose(lsofFile_p);
std::string rootsJson(buffer);
string s = rootsJson.substr(1);
s = ReplaceAll(s, "'", "");
//here my string s will contain: [{"description":"Local Disk","name":"C:\\"},{"description":"Local Disk","name":"D:\\"},{"description":"CD Drive","name":"E:\\"}]
//These are two syntax examples I found un nlohmann's docs, neither seems to work
auto j = json::parse(s);
string descr = j.value("description", "err");
I think your problem comes from number of \ in your literal string. You need 5 \ for C:\\ : C:\\\\\.
Here is a working example :
#include "json.hpp"
#include <string>
using namespace std;
using json = nlohmann::json;
int main(){
json j = json::parse("[{\"description\":\"Local Disk\",\"name\":\"C:\\\\\"},{\"description\":\"Local Disk\",\"name\":\"D:\\\\\"},{\"description\":\"CD Drive\",\"name\":\"E:\\\\\"}]");
cout << j.is_array() << endl;
for (auto& element : j) {
std::cout << "description : " << element["description"] << " | " << " name : " << element["name"] << '\n';
}
return 0;
}

swscanf_s causes error when reading into a wchar_t array

I am writing a simple serialization using the format L"79349 Dexter 03 05"
(Assume that the Dexter part will be always 1 word.)
This string is to be read into 3 ints and a wchar_t array
I currently have the following code:
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
int main()
{
int id=-1,season=-1,episode=-1;
wchar_t name[128];
swscanf_s(L"79349 Dexter 03 05", L"%d %ls %d %d", &id, name, &season, &episode);
wcout << "id is " << id << endl;
wcout << "name is " << wstring(name) << endl; //wprintf(L"name is %ls",name);
wcout << "season is " << season << endl;
wcout << "episode is " << episode << endl;
}
The code above is compiled(in VS '13) without a problem, however, when executed it crashes. Using the debug option I get the message: Unhandled exception at 0xFEFEFEFE in test3.exe: 0xC0000005: Access violation executing location 0xFEFEFEFE.
By omitting some parts, I find out that this problem is occured when reading into name.
e.g The following works just fine:
swscanf_s(L"79349 Dexter 03 05", L"%d %*ls %d %d", &id, &season, &episode);
What am i doing wrong?
My guess is that I am missing something simple and trivial but cannot find out on my own. Thanks in advance.
My reputation is currently too little to comment. As Brett says, you need to use wcstok_s. What you're trying to do is "tokenise" the long string into smaller token strings. This is what wcstok_s will do for you. On the other hand, swscanf_s will attempt to convert the whole string that you pass into the first format argument.
The other reason this isn't working for you is because you haven't specified how many bytes to scan. The "_s" versions are more "secure" in that they protect from buffer overruns which can corrupt memory and cause all sorts of problems. If you replace your:
swscanf_s(L".IHATECPP.",L".%ls.",name);
with
swscanf_s(L".IHATECPP.", L".%ls.", name, _countof(name));
the result will be: IHATECPP.. The first "." (dot) isn't parsed.
This question: Split a string in C++? might help you if you can use more C++-style routines instead of the older C-style ones. If you can't for whatever reason, then this: C++ Split Wide Char String might give you some ideas instead, as it's using wcstok(). Once wcstok_s has split the original strings into smaller substrings (tokens), then you'll need to convert to integer the ones you know are going to be so.
In general, you can search for "C++ tokenize" and you should find a lot of examples.

C++ boost/regex regex_search

Consider the following string content:
string content = "{'name':'Fantastic gloves','description':'Theese gloves will fit any time period.','current':{'trend':'high','price':'47.1000'}";
I have never used regex_search and I have been searching around for ways to use it - I still do not quite get it. From that random string (it's from an API) how could I grab two things:
1) the price - in this example it is 47.1000
2) the name - in this example Fantastic gloves
From what I have read, regex_search would be the best approach here. I plan on using the price as an integer value, I will use regex_replace in order to remove the "." from the string before converting it. I have only used regex_replace and I found it easy to work with, I don't know why I am struggling so much with regex_search.
Keynotes:
Content is contained inside ' '
Content id and value is separated by :
Conent/value are separated by ,
Value of id's name and price will vary.
My first though was to locate for instance price and then move 3 characters ahead (':') and gather everything until the next ' - however I am not sure if I am completely off-track here or not.
Any help is appreciated.
boost::regex would not be needed. Regular expressions are used for more general pattern matching, whereas your example is very specific. One way to handle your problem is to break the string up into individual tokens. Here is an example using boost::tokenizer:
#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>
#include <map>
int main()
{
std::map<std::string, std::string> m;
std::string content = "{'name':'Fantastic gloves','description':'Theese gloves will fit any time period.','current':{'trend':'high','price':'47.1000'}";
boost::char_separator<char> sep("{},':");
boost::tokenizer<boost::char_separator<char>> tokenizer(content, sep);
std::string id;
for (auto tok = tokenizer.begin(); tok != tokenizer.end(); ++tok)
{
// Since "current" is a special case I added code to handle that
if (*tok != "current")
{
id = *tok++;
m[id] = *tok;
}
else
{
id = *++tok;
m[id] = *++tok; // trend
id = *++tok;
m[id] = *++tok; // price
}
}
std::cout << "Name: " << m["name"] << std::endl;
std::cout << "Price: " << m["price"] << std::endl;
}
Link to live code.
As the string you are attempting to parse appears to be JSON (JavaScript Object Notation), consider using a specialized JSON parser.
You can find a comprehensive list of JSON parsers in many languages including C++ at http://json.org/. Also, I found a discussion on the merits of several JSON parsers for C++ in response to this SO question.

Boost xpressive regex results in garbage character

I am trying to write some code that changes a string like "/path/file.extension" to another specified extension. I am trying to use boost::xpressive to do so. But, I am having problems. It appears that a garbage character appears in the output:
#include <iostream>
#include <boost/xpressive/xpressive.hpp>
using namespace boost::xpressive;
using namespace std;
int main()
{
std::string str( "xml.xml.xml.xml");
sregex date = sregex::compile( "(\\.*)(\\.xml)$");
std::string format( "\1.zipxml");
std::string str2 = regex_replace( str, date, format );
std::cout << "str = " << str << "\n";
std::cout << "str2 = " << str2 << "\n";
return 0;
}
Now compile and run it:
[bitdiot#kantpute foodir]$ g++ badregex.cpp
[bitdiot#kantpute foodir]$ ./a.out > output
[bitdiot#kantpute foodir]$ less output
[bitdiot#kantpute foodir]$ cat -vte output
str = xml.xml.xml.xml$
str2 = xml.xml.xml^A.zipxml$
In the above example, I redirect output to a file, and use cat to print out the non-printable character. Notice the ctrl-A in the str2.
Anyways, am I using boost libraries incorrectly? Is this a boost bug? Is there another regular expression I can use that can allow me to string replace the ".tail" with some other string? (It's fix in my example.)
thanks.
At least as I'm reading things, the culprit is right here: std::string format( "\1.zipxml");.
You forgot to escape the backslash, so \1 is giving you a control-A. You almost certainly want \\1.
Alternatively (if your compiler is new enough) you could use a raw string instead, so it would be something like: R"(\1.zipxml)", and you wouldn't have to escape your backslashes. I probably wouldn't bother to mention this, except for the fact that if you're writing REs in C++ strings, raw strings are pretty much your new best friend (IMO, anyway).
As Jerry Coffin pointed out to me. It was a stupid mistake on my part.
The errant code is the following:
std::string format( "\1.zipxml");
This should be replaced with:
std::string format( "$1.zipxml");
Thanks for your help everyone.

formatting a string which contains quotation marks

I am having problem formatting a string which contains quotationmarks.
For example, I got this std::string: server/register?json={"id"="monkey"}
This string needs to have the four quotation marks replaced by \", because it will be used as a c_str() for another function.
How does one do this the best way on this string?
{"id"="monkey"}
EDIT: I need a solution which uses STL libraries only, preferably only with String.h. I have confirmed I need to replace " with \".
EDIT2: Nvm, found the bug in the framework
it is perfectly legal to have the '"' char in a C-string. So the short answer is that you need to do nothing. Escaping the quotes is only required when typing in the source code
std::string str("server/register?json={\"id\"=\"monkey\"}")
my_c_function(str.c_str());// Nothing to do here
However, in general if you want to replace a substring by an other, use boost string algorithms.
#include <boost/algorithm/string/replace.hpp>
#include <iostream>
int main(int, char**)
{
std::string str = "Hello world";
boost::algorithm::replace_all(str, "o", "a"); //modifies str
std::string str2 = boost::algorithm::replace_all_copy(str, "ll", "xy"); //doesn't modify str
std::cout << str << " - " << str2 << std::endl;
}
// Displays : Hella warld - Hexya warld
If you std::string contains server/register?json={"id"="monkey"}, there's no need to replace anything, as it will already be correctly formatted.
The only place you would need this is if you hard-coded the string and assigned it manually. But then, you can just replace the quotes manually.