Converting a json value that keeps changing to int in c++ - c++

Okay so i get this JSON object from my client:
{"command":"BrugerIndtastTF","brugerT":"\"10\"","brugerF":"\"20\""}
Then i need to use the int value from "brugerT", but as you can see it has "\"10\"" around it. When i code this in javascript i dont get this problem. Is there a way to only use the part of "brugerT" that says 10?
the code where *temp only should print the int value 10:
socket_->hub_.onMessage([this](
uWS::WebSocket<uWS::SERVER> *ws,
char* message,
size_t length,
uWS::OpCode opCode
)
{
std::string data = std::string(message,length);
std::cout << "web::Server:\t Data received: " << data << std::endl;
// handle manual settings
std::cout << "Web::Server:\t Received request: manual. Redirecting message." << std::endl;
json test1 = json::parse(data);
auto test2 = test1.json::find("command");
std::cout << "Web::Server:\t Test 1" << test1 << std::endl;
std::cout << "Web::Server:\t Test 2" << *test2 << std::endl;
if (*test2 =="BrugerIndtastTF")
{
std::cout<<"Web::Server:\t BrugerIndtastTF modtaget" << std::endl;
auto temp= test1.json::find("brugerT");
auto humi= test1.json::find("brugerF");
std::cout << "Web::Server:\t temp: " << *temp << "humi: " << *humi << std::endl;
}
});
EDIT:
Here you can see the terminal
it should just say: temp: 10 humi: 20

You can try to get the string value of brugerT and strip the \" out of the string and then convert the resulting string into a int with stoi. You could even use a regular expression to find the integer inside the string and let that library figure out what is the best matching method. A regular expression for that would be something like: ([0-9]+)
ps string literal type 6 might be of some use when manually filtering out \"
#include <iostream>
#include <regex>
#include <string>
using namespace std;
int main() {
string inputStr(R"("\"10\"")");
regex matchStr(R"(([0-9]+))");
auto matchesBegin = sregex_iterator(inputStr.begin(), inputStr.end(), matchStr);
auto matchesEnd = sregex_iterator();
for (sregex_iterator i = matchesBegin; i != matchesEnd; ++i) {
cout << i->str() << endl;
}
return 0;
}

Related

How to detect if the whole string wasn't parsed with c++

I'm trying to parse a string to detect if it is a number or if it is a name, etc.
And to do it I'm putting examples like "10 ms": it parses the 10 only, without returning an error.
What I want to do is to get if the whole string can be parsed or not, not only a part of it.
Here is my code:
string s = "10 ms";
bool number = true;
try {
stof(s, nullptr);
} catch (invalid_argument){
number = false;
}
It returns that is a number. And the returned number from stof is 10.
I have also tried using catch(...), same problem.
Looking at the documentation of std::stof, it has 2 arguments, of which one is an output argument.
This can be used the following way:
#include <string>
#include <iostream>
int main(int, char**)
{
try
{
std::string s = "10 ms";
bool number = true;
std::size_t nofProcessedChar = 0;
auto nr = std::stof(s, &nofProcessedChar);
std::cout << "found " << nr << " with processed " << nofProcessedChar << std::endl;
auto allCharsProcessed = nofProcessedChar == s.size();
std::cout << "all processed: " << allCharsProcessed << std::endl;
}
catch(const std::invalid_argument &)
{
std::cout << "Invalid argument " << std::endl;
}
catch (const std::out_of_range &)
{
std::cout << "Out of range" << std::endl;
}
}
Code at compiler explorer
As you can see in the output
found 10 with processed 2
all processed: 0
It prints 0 for all processed, which is the numeric casting value of bool.

cout and String concatenation

I was just reviewing my C++. I tried to do this:
#include <iostream>
using std::cout;
using std::endl;
void printStuff(int x);
int main() {
printStuff(10);
return 0;
}
void printStuff(int x) {
cout << "My favorite number is " + x << endl;
}
The problem happens in the printStuff function. When I run it, the first 10 characters from "My favorite number is ", is omitted from the output. The output is "e number is ". The number does not even show up.
The way to fix this is to do
void printStuff(int x) {
cout << "My favorite number is " << x << endl;
}
I am wondering what the computer/compiler is doing behind the scenes.
The + overloaded operator in this case is not concatenating any string since x is an integer. The output is moved by rvalue times in this case. So the first 10 characters are not printed. Check this reference.
if you will write
cout << "My favorite number is " + std::to_string(x) << endl;
it will work
It's simple pointer arithmetic. The string literal is an array or chars and will be presented as a pointer. You add 10 to the pointer telling you want to output starting from the 11th character.
There is no + operator that would convert a number into a string and concatenate it to a char array.
adding or incrementing a string doesn't increment the value it contains but it's address:
it's not problem of msvc 2015 or cout but instead it's moving in memory back/forward:
to prove to you that cout is innocent:
#include <iostream>
using std::cout;
using std::endl;
int main()
{
char* str = "My favorite number is ";
int a = 10;
for(int i(0); i < strlen(str); i++)
std::cout << str + i << std::endl;
char* ptrTxt = "Hello";
while(strlen(ptrTxt++))
std::cout << ptrTxt << std::endl;
// proving that cout is innocent:
char* str2 = str + 10; // copying from element 10 to the end of str to stre. like strncpy()
std::cout << str2 << std::endl; // cout prints what is exactly in str2
return 0;
}

How to save specific values in a list to txt using jsoncpp?

I have yahoo finance json file from which I want to isolate Date,Close and volume from the quote list and save it in the same order with a comma separtion in a single text file. This is my json script.
Json::Value root; // will contains the root value after parsing.
Json::Reader reader;
bool parsingSuccessful = reader.parse( YahooJson, root );
if(not parsingSuccessful)
{
// Report failures and their locations
// in the document.
std::cout<<"Failed to parse JSON"<<std::endl
<<reader.getFormatedErrorMessages()
<<std::endl;
return 1;
}else{
std::cout<<"\nSucess parsing json\n"<<std::endl;
std::cout << root<< std::endl;
std::cout <<"No of Days = "<< root["query"]["count"].asInt() << std::endl;
//below for loop returns an error
for (auto itr : root["query"]["result"]["quote"]) {
std::string val = itr.asString();
}
}
I was able to succed in fetching the json values and print root["query"]["count"].asInt() but when I go to the list values(quote) I dont know how to iterate through quote (query->result->quote) to get Date,close and volume values?
EDIT
Also tried this method
const Json::Value& quotes = root["query"]["results"]["quote"];
for (int i = 0; i < quotes.size(); i++){
std::cout << " Date: " << quotes[i]["Date"].asString();
std::cout << " Close: " << quotes[i]["Close"].asFloat();
std::cout << " Volume: " << quotes[i]["Volume"].asFloat();
std::cout << std::endl;
}
It works only when output was Date. For close and volume output it exits with a runtime error message and also this error
what() type is not convertible to string
You haven't specified which JSON library you are using, and I don't know the Yahoo finance data well enough to know the exact field names, but if you are using the JsonCpp library, which has documentation here, and you are asking about how to iterate over a JSON array, then one way to do it using iterators would look something like this
const Json::Value quote = root["query"]["results"]["quote"];
for (Json::ValueConstIterator itr = quote.begin(); itr != quote.end(); ++itr)
{
const Json::Value date = (*itr)["Date"];
const Json::Value close = (*itr)["Close"];
const Json::Value volume = (*itr)["Volume"];
std::cout << "Date: " << date.asString() << std::endl;
std::cout << "Close: " << close.asString() << std::endl;
std::cout << "Volume: " << volume.asString() << std::endl;
}

Correct usage of Poco C++ JSON for parsing data

Can anyone instruct me on how the Poco C++ JSON works?
Previously I've used JsonReader and JsonToken. The Poco C++ library doesn't seem to have corresponding objects.
How do I for example use the json parser to create a object name consisting the JSON value at the tag name?
EDIT: as of 1.5.2, things were simplified by making DefaultHandler, well ... default (and renaming it to its proper name - ParseHandler. So, if all you need is parsing, no need to explicitly provide the handler anymore:
// objects
std::string json = "{ \"test\" : { \"property\" : \"value\" } }";
Parser parser;
Var result = parser.parse(json);
Object::Ptr object = result.extract<Object::Ptr>();
Var test = object->get("test");
object = test.extract<Object::Ptr>();
test = object->get("property");
std::string value = test.convert<std::string>();
// array of objects
std::string json = "[ {\"test\" : 0}, { \"test1\" : [1, 2, 3], \"test2\" : 4 } ]";
Parser parser;
Var result = parser.parse(json);
Array::Ptr arr = result.extract<Array::Ptr>();
Object::Ptr object = arr->getObject(0);//
assert (object->getValue<int>("test") == 0);
object = arr->getObject(1);
arr = object->getArray("test1");
result = arr->get(0);
assert (result == 1);
See this answer for more details.
#include <iostream>
#include <string>
#include <Poco/JSON/JSON.h>
#include <Poco/JSON/Parser.h>
#include <Poco/Dynamic/Var.h>
using namespace std;
using namespace Poco::JSON;
string GetValue(Object::Ptr aoJsonObject, const char *aszKey) {
Poco::Dynamic::Var loVariable;
string lsReturn;
string lsKey(aszKey);
// Get the member Variable
//
loVariable = aoJsonObject->get(lsKey);
// Get the Value from the Variable
//
lsReturn = loVariable.convert<std::string>();
return lsReturn;
}
int main(int argc, char *argv[]) {
string lsJson;
Parser loParser;
lsJson = "{\"TransactionCode\":\"000000\",\"FileRecordSequenceNumber\":\"111111\",\"TcrSequenceNumber\":\"222222\",\"TransactionRouteIndicator\":\"ABCDE\",\"MerchantEstablishmentNumber\":\"00000000000\",\"MerchantName\":\"BBBBBBBBB\",\"MerchantCity\":\"CCCCCCCC\"}";
cout << lsJson << endl;
// Parse the JSON and get the Results
//
Poco::Dynamic::Var loParsedJson = loParser.parse(lsJson);
Poco::Dynamic::Var loParsedJsonResult = loParser.result();
// Get the JSON Object
//
Object::Ptr loJsonObject = loParsedJsonResult.extract<Object::Ptr>();
// Get the values for the member variables
//
//
cout << "TransactionCode " << GetValue(loJsonObject, "TransactionCode") << endl;
cout << "FileRecordSequenceNumber " << GetValue(loJsonObject, "FileRecordSequenceNumber") << endl;
cout << "TcrSequenceNumber " << GetValue(loJsonObject, "TcrSequenceNumber") << endl;
cout << "TransactionRouteIndicator " << GetValue(loJsonObject, "TransactionRouteIndicator") << endl;
cout << "MerchantEstablishmentNumber " << GetValue(loJsonObject, "MerchantEstablishmentNumber") << endl;
cout << "MerchantName " << GetValue(loJsonObject, "MerchantName") << endl;
cout << "MerchantCity " << GetValue(loJsonObject, "MerchantCity") << endl;
return 0;
}
Results:
{"TransactionCode":"000000","FileRecordSequenceNumber":"111111","TcrSequenceNumber":"222222","TransactionRouteIndicator":"ABCDE","MerchantEstablishmentNumber":"00000000000","MerchantName":"BBBBBBBBB","MerchantCity":"CCCCCCCC"}
TransactionCode 000000
FileRecordSequenceNumber 111111
TcrSequenceNumber 222222
TransactionRouteIndicator ABCDE
MerchantEstablishmentNumber 00000000000
MerchantName BBBBBBBBB
MerchantCity CCCCCCCC

Mysterious line break in cout statement

I wrote a small snippet to search for matched strings in an array, then output results for parallel arrays in a nicely formatted fashion. However, I must have some fundamental misunderstanding about how string outputs work, because for the life of me I cannot get this to output correctly, no matter where I put the tab, the newline, or whether I use an endl in my code.
Here is the relevant code below:
for (int i = 0; i < arrayCount; i++) {
if (arrayCopy[i].find(localString) != string::npos) {
cout << "\n\t"
<< array1[i] << " {"
<< subArray1[i] << ", "
<< subArray2[i] << "}";
}
}
I'm expecting results to have a tab at start of each line:
MatchedString1 {Data, MoreData}
MatchedString2 {Data, MoreData}
MatchedString3 {Data, MoreData}
Instead I am getting results like below, where the tabs appear on blank lines (except for the first result):
MatchedString1 {Data, MoreData}
MatchedString2 {Data, MoreData}
MatchedString3 {Data, MoreData}
What devilish quirk exists in c++ that is causing me so much pain?!
Using the following source to recreate your problem:
$ cat test.cpp
#include <iostream>
#include <string>
int main() {
using std::cout;
using std::string;
const std::string array1[] = {"MatchedString1", "MatchedString2", "MatchedString3"};
const std::string arrayCopy[] = {"MatchedString1", "MatchedString2", "MatchedString3"};
const std::string localString = "String";
const std::string subArray1[] = {"Data", "Data", "Data"};
const std::string subArray2[] = {"More data", "More data", "more data"};
const unsigned int arrayCount = 3;
for (int i = 0; i < arrayCount; i++) {
if (arrayCopy[i].find(localString) != string::npos) {
cout << "\n\t"
<< array1[i] << " {"
<< subArray1[i] << ", "
<< subArray2[i] << "}";
}
}
}
Compile and run:
$ g++ test.cpp
$ ./a.out
MatchedString1 {Data, More data}
MatchedString2 {Data, More data}
MatchedString3 {Data, more data}
Conclusion:
The extra line-breaks are in your data.
Suggestion:
Use square brackets to delineate your input:
std::cout << "[" << array1[i] << "] {[" << subArray1[i] << "], [" << subArray2[i] << "]}" << std::endl;
Stripping the strings:
If you find you need to strip your strings, you may find the following functions useful:
std::string lstrip(const std::string& s, const char* chars = " \t\r\n")
{
std::string::size_type begin = s.find_first_not_of(chars);
if (begin == std::string::npos)
{
return "";
}
return std::string(s, begin);
}
std::string rstrip(const std::string& s, const char* chars = " \t\r\n")
{
std::string::size_type end = s.find_last_not_of(chars);
return std::string(s, 0, end + 1);
}
std::string strip(const std::string& s)
{
return lstrip(rstrip(s));
}
Use like this:
std::cout << "\t"
<< strip(array1[i]) << " {"
<< strip(subArray1[i]) << ", "
<< strip(subArray2[i]) << "}"
<< std::endl;
(Restating my comment as a possible answer.)
The standard approach is to always put the \n at the end and everything else in the order it appears.
The only thing I can think of that would break this is a \r at the beginning of the second and third matched strings. (Someone else rightly observed that the double-spacing suggests a \n at the beginning of the input.)
Are you sure this isn't just somethin silly like "MatchedString" actually being "\nMatchedString"? You could try printing some extra stuff there to delineate your whitespace more clearly.