C++ Extract int from string using stringstream - c++

I am trying to write a short line that gets a string using getline and checks it for an int using stringstream. I am having trouble with how to check if the part of the string being checked is an int. I've looked up how to do this, but most seem to throw exceptions - I need it to keep going until it hits an int.
Later I will adjust to account for a string that doesn't contain any ints, but for now any ideas on how to get past this part?
(For now, I'm just inputting a test string rather than use getline each time.)
int main() {
std::stringstream ss;
std::string input = "a b c 4 e";
ss.str("");
ss.clear();
ss << input;
int found;
std::string temp = "";
while(!ss.eof()) {
ss >> temp;
// if temp not an int
ss >> temp; // keep iterating
} else {
found = std::stoi(temp); // convert to int
}
}
std::cout << found << std::endl;
return 0;
}

You could make of the validity of stringstream to int conversion:
int main() {
std::stringstream ss;
std::string input = "a b c 4 e";
ss << input;
int found;
std::string temp;
while(std::getline(ss, temp,' ')) {
if(std::stringstream(temp)>>found)
{
std::cout<<found<<std::endl;
}
}
return 0;
}

While your question states that you wish to
get a string using getline and checks it for an int
using stringstream, it's worth noting that you don't need stringstream at all. You only use stringstreams when you want to do parsing and rudimentary string conversions.
A better idea would be to use functions defined by std::string to find if the string contains numbers as follows:
#include <iostream>
#include <string>
int main() {
std::string input = "a b c 4 e 9879";//I added some more extra characters to prove my point.
std::string numbers = "0123456789";
std::size_t found = input.find_first_of(numbers.c_str());
while (found != std::string::npos) {
std::cout << found << std::endl;
found = input.find_first_of(numbers.c_str(), found+1);
}
return 0;
}
And then perform the conversions.
Why use this? Think about happens if you use a stringstream object on something like the following:
"abcdef123ghij"
which will simply be parsed and stored as a regular string.

Exceptions should not scary you.
int foundVal;
found = false;
while(!found || !ss.eof()) {
try
{
foundVal = std::stoi(temp); //try to convert
found = true;
}
catch(std::exception& e)
{
ss >> temp; // keep iterating
}
}
if(found)
std::cout << foundVal << std::endl;
else
std::cout << "No integers found" << std::endl;

Related

C++ Cannot return all Variables that have been added to a Vector List

In the program im currently writing, im up to a stage that requires the use of data that has been read through a file. Some of this data contains number elements, so the proper conversions have been done in order to store them in a vector of type string. Up to this point works.
I have a function called robotComplexity, which calculates a value based on other values found in the file, which have already been added to a vector List(all code shall be posted below). The text file contains the following data.
A:Head:1:2:15.
B:Torso:0:6:5.
C:Leg:0:4:6.
D:Arm:0:4:8.
E:Tail:0:6:2.
As seen in the code below, this file has been split by a dilimiter at the colon and fullstop to first seperate the variables, then the records. The variables have been stored in their respective holders as shown in the code. The function called robotComplexity contains a for loop
for(std::size_t i=0; i< partsVector.size(); ++i) {
if(partsVector[i] == userChoice) {
cout << userChoice << stoi(stringMaximum) << endl;
}
The issues with my Code stem from this for loop. The program is able to loop through the file and recongise the first variable, partCode(converted to newChar) of respective values A,B,C,D,E. So for example when a user enters A it returns A, enters B returns B etc. Now my issues come from trying to print out other variables stored in the vector. In the cout << userChoice...etc line, it successfully returns the Letter(example A) but does not return the correct Value for stringMaximum converted to an int. The returned value is 0 where it should be whatever it equals for a partCode A(in this case)
Im asking if anyone could create/fix my for loop such that when cout << "Variable" is called, it can successfuly print to the console the value of that variable according to the partCode
For Example, if the user enters A as the partcode the output should be
code
cout << userChoice << partName << stringMaximum << stringMinimum << stringComplexity << endl;
output
A
Head
1
2
15
file containing functions
struct Part {
char partCode;
std::string partName;
int maximum;
int minimum;
int complexity;
} myPart;
std::vector<string> partsVector;
std::ifstream partsList("Parts.txt");
std::string outputFile = "output.txt";
std::string input;
std::string newChar;
std::stringstream convertChar;
std::string stringMaximum = std::to_string(myPart.maximum);
std::string stringMinimum = std::to_string(myPart.minimum);
std::string stringComplexity = std::to_string(myPart.complexity);
void readFile() //function to read Builders, Customers and Parts text file
{
std::string line;
while (std::getline(partsList, line)) {
line.pop_back();//removing '.' at end of line
std::string token;
std::istringstream ss(line);
convertChar << myPart.partCode;
convertChar >> newChar;
// then read each element by delimiter
int counter = 0;//number of elements you read
while (std::getline(ss, token, ':')) {//spilt into different records
switch (counter) {//put into appropriate value-field according to element-count
case 0:
newChar = token; //convert partCode from a char to a string
break;
case 1:
myPart.partName = token;
break;
case 2:
myPart.maximum =stoi(token);
break;
case 3:
myPart.minimum = stoi(token);
break;
case 4:
myPart.complexity = stoi(token);
break;
default:
break;
}
counter++;//increasing counter
}
partsVector.push_back(newChar);
partsVector.push_back(myPart.partName);
partsVector.push_back(stringMaximum);
partsVector.push_back(stringMinimum);
partsVector.push_back(stringComplexity);
}
}
double robotComplexity() {
double complexity;
string userChoice;
cout << "Enter a part code A ,B ,C ,D or E" << endl;
cin >> userChoice;
for(std::size_t i=0; i< partsVector.size(); ++i) {
if(partsVector[i] == userChoice) {
cout << userChoice << stoi(stringMaximum) << endl;
}
}
}
Thankyou for any help offered. If any furuther explaination is required please feel free to ask. PS I know global variables aren't the best to use, but once my functions operate correctly I will clean the code up with local variables.
There are several issues here, but your main problem is that
std::string stringMaximum = std::to_string(myPart.maximum);
std::string stringMinimum = std::to_string(myPart.minimum);
std::string stringComplexity = std::to_string(myPart.complexity);
are global variables, and not functions. They will be evaluated only once at the beginning of your program. So your readFile is already broken in the code that you gave us. The first thing I would do is remove the global state (i.e. remove all global variables) and fix the code that doesn't compile anymore.
You do
partsVector.push_back(stringMaximum);
partsVector.push_back(stringMinimum);
in readFile without ever setting those two variables so you always push the same value in your vector.
Next question is, why do you use a vector of string and not a vector of Part? You already parse the file to Part objects, so just use them. Furthermore, you want to access those parts via a user input that queries for Part.partCode, so we can use a lookup table with partCode as a key (std::unordered_map<char, Part> in this case).
All in all this would look like the following (the inner while loop in readFile was a nightmare too, so I removed that aswell):
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
#include <iostream>
#include <unordered_map>
struct Part
{
char partCode = 0;
std::string partName;
int maximum = 0;
int minimum = 0;
int complexity = 0;
};
std::stringstream partsList(
R"(A:Head:1:2:15.
B:Torso:0:6:5.
C:Leg:0:4:6.
D:Arm:0:4:8.
E:Tail:0:6:2.)");
std::string outputFile = "output.txt";
std::string input;
std::unordered_map<char, Part> readFile() //function to read Builders, Customers and Parts text file
{
std::unordered_map<char, Part> parts;
std::string line;
while (std::getline(partsList, line))
{
line.pop_back(); //removing '.' at end of line
std::string token;
std::istringstream ss(line);
Part part;
std::getline(ss, token, ':');
part.partCode = token[0];
std::getline(ss, part.partName, ':');
std::getline(ss, token, ':');
part.maximum = std::stoi(token);
std::getline(ss, token, ':');
part.minimum = std::stoi(token);
std::getline(ss, token, ':');
part.complexity = std::stoi(token);
parts.emplace(part.partCode, std::move(part));
}
return parts;
}
double robotComplexity(std::unordered_map<char, Part> const& parts)
{
double complexity = 10;
char partCode;
std::cout << "Enter a part code A ,B ,C ,D or E" << std::endl;
std::cin >> partCode;
auto const& part = parts.at(partCode);
std::cout << part.maximum;
if (complexity > 100)
{
complexity = 100;
}
std::cout << "\nThe Robot Complexity is: " << complexity << std::endl;
return complexity;
}
void writeFile() //writes to a file output.txt the end calculations.
{
}
int main()
{
auto parts = readFile();
writeFile();
robotComplexity(parts);
return 0;
}

parse a string with regexp

What is the best way if you want to read a input like this:
(1,13) { (22,446) (200,66) (77,103) }
(779,22) {  } // this is also possible, but always (X,X) in the beginning
I would like to use regular expressions for doing it. But there is little info on usage of reqexp when parsing a string with more than only numbers. Currently im trying something similar with sscanf (from the c-library):
string data;
getline(in, data); // format: (X,X) { (Y,Y)* }
stringstream ss(data);
string point, tmp;
ss >> point; // (X,X)
// (X,X) the reason for three is that they could be more than one digit.
sscanf(point.c_str(), "(%3d,%3d)", &midx, &midy);
int x, y;
while(ss >> tmp) // { (Y,Y) ... (Y,Y) }
{
if(tmp.size() == 5)
{
sscanf(tmp.c_str(), "(%3d,%3d)", &x, &y);
cout << "X: " << x << " Y: " << y << endl;
}
}
The problem is that this does not work, as soon as there is more than one digit sscanf does not read the numbers. So is this the best way to go, or is there a better solution with regexp? I don´t want to use boost or something like that as this is part of a school assignment.
Maybe the following piece of code matches your requirements:
#include <iostream>
#include <string>
#include <regex>
int main()
{
std::smatch m;
std::string str("(1,13) { (22,446) (200,66) (77,103) }");
std::string regexstring = "(\\(\\s*\\d+\\s*,\\s*\\d+\\s*\\))\\s*(\\{)(\\s*\\(\\s*\\d+\\s*,\\s*\\d+\\s*\\)\\s*)*\\s*(\\})";
if (std::regex_match(str, m, std::regex(regexstring))) {
std::cout << "string literal matched" << std::endl;
std::cout << "matches:" << std::endl;
for (std::smatch::iterator it = m.begin(); it != m.end(); ++it) {
std::cout << *it << std::endl;
}
}
return 0;
}
Output:
Assuming you're using C++11, you could use something like: std::regex pattern(r"\((\d+),(\d+)\)\s*\{(\s*\(\d+,\d+\))+\s*\}") (Disclaimer: This hasn't been tested), and then use it like so:
std::smatch match;
while (ss >> tmp) {
if (std::regex_match(tmp, match, pattern)) {
// match[0] contains the first number as a string
// match[1] contains the second number as a string
// match[2] contains the list of points
}
}

How do you parse a c-string?

Hi I'm trying to take a c-string from a user, input it into a queue, parse the data with a single space depending on its contents, and output the kind of data it is (int, float, word NOT string).
E.g. Bobby Joe is 12 in 3.5 months \n
Word: Bobby
Word: Joe
Word: is
Integer: 12
Word: in
Float: 3.5
Word: months
Here's my code so far:
int main()
{
const int maxSize = 100;
char cstring[maxSize];
std::cout << "\nPlease enter a string: ";
std::cin.getline(cstring, maxSize, '\n');
//Keyboard Buffer Function
buffer::keyboard_parser(cstring);
return EXIT_SUCCESS;
}
Function:
#include <queue>
#include <string>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <vector>
namespace buffer
{
std::string keyboard_parser(char* input)
{
//Declare Queue
std::queue<std::string> myQueue;
//Declare String
std::string str;
//Declare iStringStream
std::istringstream isstr(input);
//While Loop to Read iStringStream to Queue
while(isstr >> str)
{
//Push onto Queue
myQueue.push(str);
std::string foundDataType = " ";
//Determine if Int, Float, or Word
for(int index = 0; index < str.length(); index++)
{
if(str[index] >= '0' && str[index] <= '9')
{
foundDataType = "Integer";
}
else if(str[index] >= '0' && str[index] <= '9' || str[index] == '.')
{
foundDataType = "Float";
break;
}
else if(!(str[index] >= '0' && str[index] <= '9'))
{
foundDataType = "Word";
}
}
std::cout << "\n" << foundDataType << ": " << myQueue.front();
std::cout << "\n";
//Pop Off of Queue
myQueue.pop();
}
}
}
Right now with this code, it doesn't hit the cout statement, it dumps the core.
I've read about using the find member function and the substr member function, but I'm unsure of how exactly I need to implement it.
Note: This is homework.
Thanks in advance!
UPDATE: Okay everything seems to work! Fixed the float and integer issue with a break statement. Thanks to everyone for all the help!
Your queue is sensible: it contains std::strings. Unfortunately, each of those is initialised by you passing cstring in without any length information and, since you certainly aren't null-terminating the C-strings (in fact, you're going one-off-the-end of each one), that's seriously asking for trouble.
Read directly into a std::string.
std::istreams are very useful for parsing text in C++... often with an initial read of a line from a string, then further parsing from a std::istringstream constructed with the line content.
const char* token_type(const std::string& token)
{
// if I was really doing this, I'd use templates to avoid near-identical code
// but this is an easier-to-understand starting point...
{
std::istringstream iss(token);
int i;
char c;
if (iss >> i && !(iss >> c)) return "Integer";
}
{
std::istringstream iss(token);
float f;
char c; // used to check there's no trailing characters that aren't part
// of the float value... e.g. "1Q" is not a float (rather, "word").
if (iss >> f && !(iss >> c)) return "Float";
}
return "Word";
}
const int maxSize = 100; // Standard C++ won't let you create an array unless const
char cstring[maxSize];
std::cout << "\nPlease enter a string: ";
if (std::cin.getline(cstring, maxSize, '\n'))
{
std::istringstream iss(cstring);
std::string token;
while (iss >> token) // by default, streaming into std::string takes a space-...
token_queue.push(token); // ...separated word at a time
for (token_queue::const_iterator i = token_queue.begin();
i != token_queue.end(); ++i)
std::cout << token_type(*i) << ": " << *i << '\n';
}

C++ String to Integer Issue Using atoi(str.c_str())

I am trying to represent a variable in the form of a string to a integer, I have done so using;
atoi(str.c_str())
The string is originally obtained from a text file and stored into a;
CharArrayPtr cmemblock;
Which is then represented as a string;
string str;
for(int i = 0; i < numberofvalues; i++)
{
str = cmemblock[i];
int number = atoi(str.c_str());
cout << number;
}
If I was to change the 'cout' to print str;
str = cmemblock[i];
int number = atoi(str.c_str());
cout << str;
The number show correctly as stored in the text file
However, I require the output to be an integer so that I could represent it in a loop to search for a value stored in a array. So this is where 'number' comes into play, which is the reason why I am asking for your help, when;
cout << number;
Whenever a new line is read it is represented as '0' how would I go about removing this? If your require my full code it is in several different .cpp files and to prevent anyone copying my work I can only email it you, im sure you have already guessed it is part of a University Assignment.
Using Member Adosi code I came up with this;
std::string str;
for(int i = 0; i < numberofvalues; i++)
{
str = cmemblock[i];
std::stol(str);
int number = std::stoi(str);
cout << number;
}
I get an error R6010. Have I done this wrong?
std::stoi(str)
Use this instead of atoi
C++11 has this and a few other functions such as std::stol() for longs, std::stof() for floats, etc.
http://en.cppreference.com/w/cpp/string/basic_string/stol
If you dont have C++11 for std::stoi but do have boost you could use lexical cast
#include <boost/lexical_cast.hpp>
int main()
{
std::string s = "100";
try
{
int n = boost::lexical_cast<int>(s);
std::cout << "n = " << n << std::endl;
}
catch (boost::bad_lexical_cast)
{
std::cout << "conversion failed" << std::endl;
}
}
This ensures a valid conversion can take place and throws an exception if it cannot
Regarding your Edit - This requires a C++11 Compiler to work
std::string str;
for(int i = 0; i < numberofvalues; i++)
{
str = cmemblock[i];
//std::stol(str); -> This line is unneeded as it converts string to a long
// Ideally you should check that str is valid here etc. before changing it to an int
int number = std::stoi(str);
cout << number;
}
Another option is to use std::stringstream:
#include <sstream>
#include <string>
int string_to_int(const std::string &string) {
std::stringstream s(string);
s >> number;
if (!s.good()) {
throw std::exception();
}
return s;
}
int main(int argc, const char* argv[]) {
int number = string_to_int(argv[1]);
return 0;
}
This doesn't require any external libraries or C++11, and should be compatible with any C++ compiler out there.
Edit
Fleshed out the example to show how you could write your own string_to_int function to simplify the use of std::stringstream.

Comparing data types

int item;
cin >> item;
That's in my code, but I want the user to be able to type integers or strings. This is basically what I want to do:
if(item.data_type() == string){
//stuff
}
Is this possible?
You can't do exactly that, but with a little more work you can do something similar. The following code works if you have the Boost libraries installed. It can be done without boost, but its tedious to do so.
#include <boost/lexical_cast.hpp>
main() {
std::string val;
std::cout << "Value: " << std::endl;
std::cin >> val;
try {
int i = boost::lexical_cast<int>(val);
std::cout << "It's an integer: " << i << std::endl;
}
catch (boost::bad_lexical_cast &blc) {
std::cout << "It's not an integer" << std::endl;
}
}
no, but you can input string and then convert it to integer, if it is integer.
Try to read this articles:
Use RTTI for Dynamic Type Identification
C++ Programming/RTTI
Run-time type information
What you're doing is not value C++ code. It wouldn't compile!
Your problem is:
That's in my code, but I want the user to be able to type integers or strings
Then do this:
std::string input;
cin >> input;
int intValue;
std::string strValue;
bool isInt=false;
try
{
intValue = boost::lexical_cast<int>(input);
isInt = true;
}
catch(...) { strValue = input; }
if ( isInt)
{
//user input was int, so use intValue;
}
else
{
//user input was string, so use strValue;
}