The following code converts an std::string to int and the problem lies with the fact that it cannot discern from a true integer or just a random string. Is there a systematic method for dealing with such a problem?
#include <cstring>
#include <iostream>
#include <sstream>
int main()
{
std::string str = "H";
int int_value;
std::istringstream ss(str);
ss >> int_value;
std::cout<<int_value<<std::endl;
return 0;
}
EDIT: This is the solution that I liked because it is very minimal and elegant! It doesn't work for negative numbers but I only needed positive ones anyways.
#include <cstring>
#include <iostream>
#include <sstream>
int main()
{
std::string str = "2147483647";
int int_value;
std::istringstream ss(str);
if (ss >> int_value)
std::cout << "Hooray!" << std::endl;
std::cout<<int_value<<std::endl;
str = "-2147483648";
std::istringstream negative_ss(str);
if (ss >> int_value)
std::cout << "Hooray!" << std::endl;
std::cout<<int_value<<std::endl;
return 0;
}
You may try to use Boost lexical_cast, it will throw an exception if the cast failed.
int number;
try
{
number = boost::lexical_cast<int>(str);
}
catch(boost::bad_lexical_cast& e)
{
std::cout << str << "isn't an integer number" << std::endl;
}
EDIT
Accorinding to #chris, You may also try to use std::stoi since C++11. It will throw std::invalid_argument exception if no conversion could be performed. You may find more information here: std::stoi
WhozCraig's approach is much nicer and I wanted to expand on it using the approach that the C++ FAQ uses which is as follows:
#include <iostream>
#include <sstream>
#include <string>
#include <stdexcept>
class BadConversion : public std::runtime_error {
public:
BadConversion(std::string const& s)
: std::runtime_error(s)
{ }
};
inline int convertToInt(std::string const& s,
bool failIfLeftoverChars = true)
{
std::istringstream i(s);
int x;
char c;
if (!(i >> x) || (failIfLeftoverChars && i.get(c)))
throw BadConversion("convertToInt(\"" + s + "\")");
return x;
}
int main()
{
std::cout << convertToInt( "100" ) << std::endl ;
std::cout << convertToInt( "-100" ) << std::endl ;
std::cout << convertToInt( " -100" ) << std::endl ;
std::cout << convertToInt( " -100 ", false ) << std::endl ;
// The next two will fail
std::cout << convertToInt( " -100 ", true ) << std::endl ;
std::cout << convertToInt( "H" ) << std::endl ;
}
This is robust and will know if the conversion fails, you also can optionally choose to fail on left over characters.
/* isdigit example */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main ()
{
char str[]="1776ad";
int year;
if (isdigit(str[0]))
{
year = atoi (str);
printf ("The year that followed %d was %d.\n",year,year+1);
}
return 0;
}
Related
Im trying to make a number that is positive (already converted into a string) look like "+number" instead of "number" but i can't define it in an if
#include <iostream>
#include <string>
int main()
{
std::string x3s;
int number = 145;
if (number >= 0)
{
x3s = "+" + number;
}
std::cout << x3s << std::endl;
}
Firstly, there is an I/O manipulator std::showpos.
#include <iostream>
int main()
{
int number = 145;
std::cout << std::showpos << number << std::endl;
}
Secondly, you are using the verb "define" incorrectly.
You can use x3s = std::string("+") + std::to_string(number);
Here's all the code
#include <iostream>
#include <string>
#include <windows.h>
#include <stdlib.h>
using namespace std;
void Pdelay(string str)
{
for (char c : str)
{
std::cout << "" << c << "";
Sleep(100);
}
std::cout << '\n';
}
int main()
{
int exit = 1;
while (exit == 1)
{
cout<< "Type something\n:";
string str;
str.clear();
getline(cin,str);
Pdelay(str);
cout << "\n\n[1]Type something again"<< endl;
cout << "[2]Exit\n:";
cin >> exit;
}
return 0;
}
Whenever I run it, it works properly the first time round, when it loops back it skips the getline and continues with the two cout statements.
Immediately after you use cin, the newline remains in the buffer and is being "eaten" by the subsequent getline. You need to clear the buffer of that additional newline:
// immediately after cin (need to #include <limits>)
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
That's why it's not a very good idea to combine std::cin and std::getline. BTW, you can write your code in fully standard compliant C++11, with no additional non-library headers:
#include <chrono>
#include <iostream>
#include <limits>
#include <string>
#include <thread>
void Pdelay(std::string str)
{
for (char c : str)
{
std::cout << "" << c << "" << std::flush;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cout << '\n';
}
int main()
{
int ext = 1;
while (ext == 1)
{
std::cout << "Type something\n:";
std::string str;
str.clear();
std::getline(std::cin, str);
Pdelay(str);
std::cout << "\n\n[1]Type something again" << std::endl;
std::cout << "[2]Exit\n:";
std::cin >> ext;
if(!std::cin) // extraction failed
{
std::cin.clear(); // clear the stream
ext = 1;
}
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
}
}
I just realized that this question has been asked (in a slightly modified form) before, and the answers are great:
Why does std::getline() skip input after a formatted extraction?
lexical_cast throws an exception in the following case. Is there a way to use lexical_cast and convert the string to integer.
#include <iostream>
#include "boost/lexical_cast.hpp"
#include <string>
int main()
{
std::string src = "124is";
int iNumber = boost::lexical_cast<int>(src);
std::cout << "After conversion " << iNumber << std::endl;
}
I understand, I can use atoi instead of boost::lexical_cast.
If I'm understanding your requirements correctly it seems as though removing the non-numeric elements from the string first before the lexical_cast will solve your problem. The approach I outline here makes use of the isdigit function which will return true if the given char is a digit from 0 to 9.
#include <iostream>
#include "boost/lexical_cast.hpp"
#include <string>
#include <algorithm>
#include <cctype> //for isdigit
struct is_not_digit{
bool operator()(char a) { return !isdigit(a); }
};
int main()
{
std::string src = "124is";
src.erase(std::remove_if(src.begin(),src.end(),is_not_digit()),src.end());
int iNumber = boost::lexical_cast<int>(src);
std::cout << "After conversion " << iNumber << std::endl;
}
The boost/lexical_cast uses stringstream to convert from string to other types,so you must make sure the string can be converted completely! or, it will throw the bad_lexical_cast exception,This is an example:
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#define ERROR_LEXICAL_CAST 1
int main()
{
using boost::lexical_cast;
int a = 0;
double b = 0.0;
std::string s = "";
int e = 0;
try
{
// ----- string --> int
a = lexical_cast<int>("123");//good
b = lexical_cast<double>("123.12");//good
// -----double to string good
s = lexical_cast<std::string>("123456.7");
// ----- bad
e = lexical_cast<int>("abc");
}
catch(boost::bad_lexical_cast& e)
{
// bad lexical cast: source type value could not be interpreted as target
std::cout << e.what() << std::endl;
return ERROR_LEXICAL_CAST;
}
std::cout << a << std::endl; // cout:123
std::cout << b << std::endl; //cout:123.12
std::cout << s << std::endl; //cout:123456.7
return 0;
}
Hello
I know it was asked many times but I hadn't found answer to my specific question.
I want to convert only string that contains only decimal numbers:
For example 256 is OK but 256a is not.
Could it be done without checking the string?
Thanks
The simplest way that makes error checking optional that I can think of is this:
char *endptr;
int x = strtol(str, &endptr, 0);
int error = (*endptr != '\0');
In C++ way, use stringstream:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
stringstream sstr;
int a = -1;
sstr << 256 << 'a';
sstr >> a;
if (sstr.failbit)
{
cout << "Either no character was extracted, or the character can't represent a proper value." << endl;
}
if (sstr.badbit)
{
cout << "Error on stream.\n";
}
cout << "Extracted number " << a << endl;
return 0;
}
An other way using c++ style : We check the number of digits to know if the string was valid or not :
#include <iostream>
#include <sstream>
#include <string>
#include <cmath>
int main(int argc,char* argv[]) {
std::string a("256");
std::istringstream buffer(a);
int number;
buffer >> number; // OK conversion is done !
// Let's now check if the string was valid !
// Quick way to compute number of digits
size_t num_of_digits = (size_t)floor( log10( abs( number ) ) ) + 1;
if (num_of_digits!=a.length()) {
std::cout << "Not a valid string !" << std::endl;
}
else {
std::cout << "Valid conversion to " << number << std::endl;
}
}
I have any sequence (or sentence) and i want to extract the last 2 strings.
For example,
sdfsdfds sdfs dfsd fgsd 3 dsfds should produce: 3 dsfds
sdfsd (dfgdg)gfdg fg 6 gg should produce: 6 gg
You can use std::string::find_last_of function to find spaces.
int main()
{
std::string test = "sdfsdfds sdfs dfsd fgsd 3 dsfds";
size_t found1 = test.find_last_of( " " );
if ( found1 != string::npos ) {
size_t found2 = test.find_last_of( " ", found1-1 );
if ( found2 != string::npos )
std::cout << test.substr(found2+1, found1-found2-1) << std::endl;
std::cout << test.substr(found1+1) << std::endl;
}
return 0;
}
The following will work if your strings are whitespace separated.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int main()
{
string str = "jfdf fhfeif shfowejef dhfojfe";
stringstream sstr(str);
vector<string> vstr;
while(sstr >> str)
{
vstr.push_back(str);
}
if (vstr.size() >= 2)
cout << vstr[vstr.size()-2] << ' ';
if (vstr.size())
cout << vstr[vstr.size()-1] << endl;
return 0;
}
Returns the strings in the wrong order, but if that doesn't matter,
std::string s ("some words here");
std::string::size_type j;
for(int i=0; i<2; ++i) {
if((j = s.find_last_of(' ')) == std::string::npos) {
// there aren't two strings, throw, return, or do something else
return 0;
}
std::cout << s.c_str()+j+1;
s = " " + s.substr(0,j);
}
Alternatively,
struct extract_two_words {
friend std::istream& operator>> (std::istream& in , extract_two_words& etw);
std::string word1;
std::string word2;
};
std::istream& operator>> (std::istream& in , extract_two_words& etw) {
std::string str1, str2;
while(in) {
in >> str1;
in >> str2;
}
etw.word2 = str1;
etw.word1 = str2;
}
I would encourage you to have a look at the Boost library. It has algorithms and data structures that help you tremendously. Here's how to solve your problem using Boost.StringAlgo:
#include <boost/algorithm/string/split.hpp>
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::string test = "sdfsdfds sdfs dfsd fgsd 3 dsfds";
std::vector<std::string> v;
boost::algorithm::split(v, test, [](char c) { return c==' ';});
std::cout << "Second to last: " << v.at(v.size()-2) << std::endl;
std::cout << "Last: " << v.at(v.size()-1) << std::endl;
}
I would also encourage you to always use the vector::at method instead of []. This will give you proper error handling.
int main()
{
std::string test = "sdfsdfds sdfs dfsd fgsd 3 dsfds";
size_t pos = test.length();
for (int i=0; i < 2; i++)
pos = test.find_last_of(" ", pos-1);
std::cout << test.substr(pos+1) << std::endl;
}
Simpler :)