How to detect if the whole string wasn't parsed with c++ - 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.

Related

What am I iterating in this find_if function?

Here is my code:
bool isNotValid (char a) {
if (isalpha(a) || a == '_')
{
cout << "\n- isalpha";
return 0;
}
else
{
cout << "\n- notalpha";
return 1;
}
}
bool test123(const string& test)
{
return find_if(test.begin(), test.end(), isNotValid) != test.end();
}
int main()
{
string test;
cout << "Test input: ";
cin >> test;
if (!test123(test))
cout << "\n- Valid\n";
else
cout << "\n- Not Valid\n";
return 0;
}
This is part of my code to check the validity of username in my program. I don't really understand what exactly I am iterating through when I insert the string into my function as address of the string. CPP reference states that find_if iterates from first to last position of a sequence.
Poked through the code with cout at different location, still didn't quite catch what is going on.
You are iterating your string. You did not pass the address of the string. The function takes the string as a reference to const, meaning it passes the actual string (no copy is made) and the function is not allowed to modify the string. You are iterating character by character in your string and calling your function isNotValid() on each character.
Notes:
Instead of returning 1 or 0 from isNotValid(), return true or false.
Consider flipping your logic and renaming the function to isValid() instead. You would also have to change test123() to use std::find_if_not(). Finally, you would check if the returned iterator is end() and not if it's not.
But, if you do change isNotValid() to isValid(), you'd be better off switching from std::find_if() entirely to to std::all_of(). It makes more sense, is more readable, and returns a bool directly (No need to compare against end()).
But if you want to keep your function isNotValid(), the comment that suggests using std::any_of() is what I would recommend for the same reasons.
Here's my take on your code:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
bool isValid(char a) {
return std::isalpha(static_cast<unsigned char>(a)) || a == '_'; // !
}
bool test123(const std::string& test) {
return std::all_of(test.begin(), test.end(), isValid); // !
}
int main() {
std::string testOne{"i_am_valid"};
std::string testTwo{"i_am_invalid_123"};
std::cout << "Testing: " << testOne << " : " << std::boolalpha
<< test123(testOne) << '\n';
std::cout << "Testing: " << testTwo << " : " << std::boolalpha
<< test123(testTwo) << '\n';
}
Output:
❯ ./a.out
Testing: i_am_valid : true
Testing: i_am_invalid_123 : false
I would argue that readability has stayed largely the same, but the mental load has been shifted; the Boolean flips make a bit more sense.
As you progress in your learning, you might not even want to have the function isValid() if it's a one-off thing. C++11 introduced lambdas, or functions as objects. C++20 also introduced ranges, so you don't have to pass a pair of iterators if you intend to iterate the whole container anyway.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
bool test123(const std::string& test) {
return std::ranges::all_of(test, [](const auto& c) {
return std::isalpha(static_cast<unsigned char>(c)) || c == '_';
}); // !
}
int main() {
std::string testOne{"i_am_valid"};
std::string testTwo{"i_am_invalid_123"};
std::cout << "Testing: " << testOne << " : " << std::boolalpha
<< test123(testOne) << '\n';
std::cout << "Testing: " << testTwo << " : " << std::boolalpha
<< test123(testTwo) << '\n';
}
That's a bit hairy to read if you're not familiar with lambdas, but I find lambdas useful for checks like this where you're just doing it the one time.

about : Scope of exception object in C++ : why don't I get the copy?

In question about scope of exception it is stated by Aj. that throw and catch clauses will create copies of the exception (unless reference is used I guess)
I tried myself a small toy code and I don't understand the result. here :
//g++ 7.4.0
#include <iostream>
using namespace std;
struct Some_error {
Some_error(float code):err_code(code){ cout << "Some_error(" << err_code << ")\n"; }
~Some_error() { cout << "~Some_error(" << err_code << ")\n"; }
Some_error(const Some_error& o):err_code(o.err_code+0.1) { cout << "Some_error(copy::" << err_code << ")\n"; }
Some_error(Some_error&& o):err_code(std::move(o.err_code)+.01){ cout << "Some_error(move::" << err_code << ")\n"; }
int get_code() const { return err_code; }
private : float err_code;
};
int do_task() {
if ( false ) return 42; else throw Some_error {1};
cout << "end do_task\n" ;
}
void taskmaster(){
try { auto result = do_task(); cout << "the answer is " << result << "\n" ; }
catch (Some_error e) { cout << "catch Some_error : " << e.get_code() << "\n" ; }
cout << "end taskmaster\n" ;
}
int main() { taskmaster(); }
the trace I get is as follows :
Some_error(1)
Some_error(copy::1.1)
catch Some_error : 1
~Some_error(1.1)
~Some_error(1)
end taskmaster
Now first, as I used no reference here, according to Aj., I would expect 2 copies to happen.
And second, there was a copy, that set err_code to 1.1, but the display is still 1.
Remark: just to be complete, I changed the catch to : catch(Some_error& e),
and then the trace looks fine to me :
Some_error(1)
catch Some_error : 1
~Some_error(1)
end taskmaster
I would expect 2 copies to happen.
Why? Only one copy is made by the catch block. Where would the second copy happen?
set err_code to 1.1, but the display is still 1.
Because get_code returns an int, so the floating point value gets truncated.

Converting a json value that keeps changing to int in 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;
}

C++ Searching an array for a number but does not trigger else statement if it is not found

int gas;
// Input Code
int user_code;
std::cout << std::endl;
std::cout << "Please enter the Code: ";
std::cin >> user_code;
std::cout << "The value you entered is " << user_code;
std::cout << std::endl;
int array1[16] = { 42011, 42017, 42029, 42045,
42091, 42101, 34001, 34005,
34007, 34009, 34011, 34015,
34033, 10001, 10003, 24015 }; // 0.2387 (23.87%)
int array2[45] = { 11001, 24003, 24510, 24005, 24009,
24013, 24017, 24019, 24021, 24025,
24027, 24029, 24031, 24033, 24035,
24037, 24041, 24043, 51510, 51013,
51043, 51047, 51600, 51059, 51610,
51061, 51069, 51630, 51099, 51107,
51683, 51685, 51153, 51157, 51177,
51179, 51187, 51840, 54003, 54027,
54037, 54065, 42001, 42055, 42133 }; //0.2710 (27.10%)
int * array1_search;
array1_search = std::find(array1, array1+ 16, user_code);
int * array2_search;
array2_search = std::find(array2, array2 + 45, user_code);
if (array1_search != array1+ 16) {
std::cout << "Codefound in Array1: " << *array1_search << '\n';
gas= 0.2387;
}
else if (array2_search != array2_search + 45) {
std::cout << "Code found in Array2: " << *array2_search << '\n';
gas= 0.2710;
}
else {
std::cout << "Not found \n";
gas= 0.1506;
}
Above is my current code. I am trying to have the user input a variable user_code value and then iterate over the two arrays array1[16] and array2[45]. If the user input value is on the first array1 I want to assign gas 0.2387 and if the input value is on the other array2 I want to assign gas 0.2710, and if it is not within any array gas should be 0.1506.
So basically I want to assign a value depending on which array the user's input is contained in. I am very new to c++, what is the best way to go about this?
It seems to work fine if I enter a number that is within array1 or array2 and it correctly identifies that is found in array1 or array2. The problem is when I enter a number I know is not within either array to trigger the else statement it identifies it as being in array2. For example, when I enter 12345 as a user_code it says "Code found in Array2: 0". I know 12345 is not contained in array2 and I do not understand why *array2_search is assigned 0. What can I do to fix this so if a user_code is entered that is not contained within array1 or array2 it goes to the else statement?
else if (array2_search != array2_search + 45) {
Should be
else if (array2_search != array2 + 45) {
or better using std::end of C++11:
if (array1_search != std::end(array1)) {
else if (array2_search != std::end(array2)) {
And int gas; => double gas; if you want to be able to store floating point values, not just integers (0.2387 and 0.2710 would give integer 0).
Using standard containers and newer c++ features if you have C++11 minimum you can then do something like this:
int main() {
// Use Constants Instead of "Hard Coded Values"
// If you noticed these are not even needed.
// const unsigned code1 = 16;
// const unsigned code2 = 45;
// Made gas a float instead of an int due to the decimal values
// I also initialized it with the default value if the code is
// not found in either container.
float gas = 0.1506f; // Default Price If Not Found
// created your first array as a const std::vector<int> and
// used its initializer list to populate its contents: this vector
// can not be modified: remove the const if this container
// will need to have entries added in the future.
const std::vector<int> arr1 { 42011, 42017, 42029, 42045,
42091, 42101, 34001, 34005,
34007, 34009, 34011, 34015,
34033, 10001, 10003, 24015 }; // 0.2387 (23.87%)
// did the same for the second array
const std::vector<int> arr2 { 11001, 24003, 24510, 24005, 24009,
24013, 24017, 24019, 24021, 24025,
24027, 24029, 24031, 24033, 24035,
24037, 24041, 24043, 51510, 51013,
51043, 51047, 51600, 51059, 51610,
51061, 51069, 51630, 51099, 51107,
51683, 51685, 51153, 51157, 51177,
51179, 51187, 51840, 54003, 54027,
54037, 54065, 42001, 42055, 42133 }; //0.2710 (27.10%)
// No changes made here same basic user I/O.
int user_code = 0;
std::cout << "Please enter the Code: ";
std::cin >> user_code;
std::cout << "The value you entered is " << user_code;
std::cout << "\n";
// Created 2 flags for later.
bool b1found = false;
bool b2found = false;
// auto for loop ranged based.
for ( auto code : arr1 ) {
if ( code == user_code ) {
b1found = true; // Set flag
gas = 0.2387f; // Set new gas
// Output code & gas
std::cout << "Code found in Arr1: " << code << '\n';
std::cout << "gas = " << gas << '\n';
}
}
for ( auto code : arr2 ) {
if ( code == user_code ) {
b2found = true; // set flag
gas = 0.2710f; // set gas
// output code & gas
std::cout << "Code found in Arr2: " << code << '\n';
std::cout << "gas = " << gas << '\n';
}
}
// If code not found in either output "not found" and display default gas
if ( !b1found && !b2found ) {
std::cout << "Not found\n";
std::cout << "gas = " << gas << '\n';
}
std::cout << "\nPress any key and enter to quit." << std::endl;
char c;
std::cin >> c;
return 0;
}
You can even simplify this a little more by removing the two bool flags. We know that if a value is found in arr1 or arr2 that the gas value will be changed, So all we really have to do is check to see if it has been changed.
// auto for loop ranged based.
for ( auto code : arr1 ) {
if ( code == user_code ) {
gas = 0.2387f; // Set new gas
// Output code & gas
std::cout << "Code found in Arr1: " << code << '\n';
std::cout << "gas = " << gas << '\n';
}
}
for ( auto code : arr2 ) {
if ( code == user_code ) {
gas = 0.2710f; // set gas
// output code & gas
std::cout << "Code found in Arr2: " << code << '\n';
std::cout << "gas = " << gas << '\n';
}
}
const float defaultGas = 0.1506;
// If code not found in either output "not found" and display default gas
if ( gas == defaultGas ) {
std::cout << "Not found\n";
std::cout << "gas = " << gas << '\n';
}

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