I'm trying to understand how can I convert multiple integers from a string. I have tried to use atoi(), stoi() and istringstream() and they all do the same thing. I can't get more than one integer.
For example, if the string is "Chocolate and Milk 250 pounds and 2 oz or 1.5 coins."
All of the above functions will not work. It won't take the whole string. If I leave only a single number then it will work. I want to be able to read the whole string and get all of the integers only (not float).
I am using a while(getline()) for the string. Then try to get it into string.
Although, if I could only return the total amount of integers in the string that would be better. Either way, I'm trying to learn both ways. In this case, the output would be "2", since there are only two int.
One way is to split the string using as delimiter and using stoi on individual strings to check if they are integers.
#include <iostream>
#include <sstream>
#include <string>
int main(){
std::string s = "Chocolate and Milk 250 pounds and 2 oz or 1.5 coins.";
int count = 0;
std::istringstream iss(s);
std::string token;
while(getline(iss,token,' ')){
if(std::isdigit(token[0]) &&stoi(token) && token.find('.')==std::string::npos){
count++;
}
}
std::cout<<count<<std::endl;
}
Note that more complex checks can be done on strings if stoi succeeds, but the input is not a valid integer. You can have a helper function which checks if all the characters are digits or not by using isdigit etc.
Related
I was given a question where the input will be like:
10 8
4 9
6 12
5 4
3
1
Here I don't know the number of lines that contains 2 integers. Those sets of 2 integers will be taken into an array. But when the program encounters "3", it will start taking input in another array.
I have tried this with
while(cin>>a>>b){ //some porcess with a and b }
but it doesn't work because it recognizes 3 and 1 as another set of two integers. Please help me to solve this problem.
cin >> a >> b skips not only spaces, but any delimeter characters too ('\n', '\t', ' ').
Here you actually may want to read input line-by-line and then check if there are two integers or one. Consider use of std::getline for retrieving each line of text. Then you can use read string as std::istream (like in example in the link above) and read from it with counting, how many numbers you read totally.
So think about your problem. Essentially it is, read one line at a time, and if it contains two numbers do one thing, but if it contains one number do something else.
But the code you have written reads numbers not lines. That is where the problem is.
Instead write your code to read only line at a time, analyse that line to see if it contains one or two numbers (or something else) and then proceed from there.
What you need is the ability to read a line of text into a string, and then read from that string into your numbers. To do that you use an istringstream. Something like this
#include <iostream>
#include <sstream>
#include <string>
int a, b;
string s;
getline(cin, s); // read one line from standard input
istringstream line(s); // put that string to a stream we can read from
if (line >> a) // try and read the first number from the stream
{
// got the first number
if (line >> b) // try and read the second number from the stream
{
// got the second number
...
}
else
{
// only one number
...
}
}
else
{
// didn't get any numbers, some sort of error
...
}
I managed to get this program to work. If the user types an unfixed amount of integers, the program will calculate the average value of it. But I need to end it with <Ctrl-D> in my terminal (end of file) in order for it to work. Why can I not just press enter for it to work?
I also believe that I've used an unnecessary amount of variables. Can it be narrowed down to maybe 2 variables?
#include <iomanip>
#include <iostream>
using namespace std;
int main ()
{
int digit {};
int res {};
int counter {};
cout << "Type in integers: ";
while (cin >> digit)
{
counter ++;
res += digit;
}
cout << "The mean was " << setw(1) << setprecision(1) << fixed << static_cast<double>(res) / static_cast<double>(counter) << endl;
return 0;
}
Why can I not just press enter for it to work?
Because that's not how the overloaded >> formatted extraction operator works. This operator skips over an unlimited amount of whitespace characters, including newline characters, until it reads the integer. It's simply how it works: it will read newlines and spaces, after newlines, and spaces, until it sees a digit. That's its mission in life: read and skip over spaces and newlines until it reads at least one digit. It never gets tired of reading newlines and spaces, and will keep going as long that's the case.
To handle input in the fashion you describe requires a completely different approach: using std::getline to read a single line of input into a std::string, up until the next newline character. Then, once that's done, you can check if the std::string is empty, which means that no input was entered, and then terminate; otherwise take the input in std::string and convert it to an int value (using std::stoi, std::from_chars, or a std::istringstream -- take your pick), and then proceed with the existing algorithm.
Can it be narrowed down to maybe 2 variables?
How do you expect to do that? Hard, immutable logic dictates that you must keep track of at least two discrete values: the total sum and the number of values read. But then you just ran out of variables. You have no more variables to use for storing the next read value (if there is one), using whatever approach you chose to use. So, you can't do it. Rules of logic require the use of at least three variables, possibly more depending on how fancy and robust you want your input validation to work.
I was trying to solve a problem. The Problem is : There is given a date string like 21/9/2013. I have to convert this date into int. I have used stoi but it is just showed first two int 21.
I want to print 21 9 2013 to the console
So you don't really need three integers. You need three strings.
With these includes:
#include <string>
#include <sstream>
using namespace std;
You can parse a string like this:
string date = "21/9/2013";
into its components, like this:
stringstream stream(date);
string s;
while (std::getline(stream, s, '/') {
cout << s << " ";
}
cout << endl;
The above should print out: 21 9 2013
If you really want integers, the above shouldn't be too hard to modify. You can use stoi on each iteration of the while loop above.
What you want to do here is tokenize the string into three different substrings ("21", "9", and "2013"); then you can call stoi() on each substring and print out the integer stoi() returned for each one.
There are various ways to tokenize a string in C++; rather than choose one to repeat here, I'll just link to the StackOverflow question and answers on that topic.
So, lets say we have a text.txt file with these numbers:
4 5 15 10 20
5 5 15 10 20 25
In the above example, the first numbers in the row describe how many numbers are in that row. The rest of the numbers are the numbers I am interested in (I will be sorting them in a later part of the code, but that is not where my question focuses).
My issue is, how can I best go about taking each row of numbers (ignoring the first number), placing them into a array, and then moving onto the next line and doing the same thing (placing them into an array, that will be later sorted)?
All my google searching points to doing this with strings via getline, and nothing really points to handling it with ints. Hope someone on here can help point me in the right direction.
Below is the basic code I would use to open the file:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int a;
ifstream inputfile;
//declare an input file
inputfile.open("text.txt");
while(//not sure best way to do this part)
{
//guessing I can use a for loop and place numbers in array
//based on first number in the row of numbers
}
return 0;
}
The most obvious way would probably be to read a line with std::getline, then put the string into a stringstream, and read numbers from there (ignoring the first, obviously).
I suggest the following approach:
std::string line;
// Keep reading lines of text from the file.
// Break out of the loop when there are no more lines in the file.
while (getline(inputfile, line)){
// Construct a istingstream from the line of text.
std::istringstream ss(line);
// Read the numbers from the istingstream.
// Process the numbers as you please.
}
I have a program that reads a credit card number. I want to add in something that makes sure that 16 numbers are added in, no letters, and as many spaces as wanted (although they don't count towards numbers). Is there a function or set of functions to do this, or should I just make a bunch of while and if loops that use isdigit() and isalpha() that goes through the array one element at a time?
char cardNum[32];
cout << "Enter credit card number: ";
cin.getline(cardNum, 32); //Read in the entire line for the name
There are numerous things you could do. One idea is to use std::find_if with a custom predicate. For example:
bool IsCharIllegal(char ch)
{
// return true or false based on whatever your exact requirements are
}
Then:
auto itFound = std::find_if(cardNum, cardNum + 32, IsCharIllegal);
if(itFound != cardNum + 32)
// invalid character was entered!
There is a case to be made for using std::string instead of a raw char array too:
std::string cardNum;
cout << "Enter credit card number: ";
std::cin >> cardNum;
Followed by:
auto itFound = std::find_if(cardNum.begin(), cardNum.end(), IsCharIllegal);
if(itFound != cardNum.end())
// invalid character was entered!
That helps avoid the magic 32 and also allows inputs of any length.
I would use a regular expression to match this pattern. If you're using C++11, you can use the built in header: http://www.cplusplus.com/reference/regex/
Otherwise, take a look here for some alternative libraries you can use: C++: what regex library should I use?
Unfortunately, I'm not very good at regular expressions, but the following should match 16 numbers with spaces inbetween.
(\d[ ]*){16}
If you're looking for more info on regular expressions, here is a good cheat sheet I use often: http://regexlib.com/CheatSheet.aspx
I also like to test my expressions using this site: http://regexpal.com/
So something like this would be allowed?
"123 456 789 01 23456"
Use std::string and the free-standing std::getline function. It's better than the member function of the same name, because it doesn't force you to deal with pointers.
std::string line;
std::getline(std::cin, line);
if (!std::cin)
{
// catastrophic input failure
}
Then you have a string as in my example above in line. You could use std::find_if to verify that there are no illegal characters and std::count_if to make sure there are exactly 16 digits, but I think writing your own loop (not "bunch of loops") would yield more readable code here.
By the way, beware of isdigit! For historical reasons, you must cast its argument to unsigned char in order to use it safely.
There is an atoll function in the cstdlib. http://www.cplusplus.com/reference/cstdlib/atoll/
It converts character string input into a long long, which could store a 16 digit long credit card number, however this quits as soon as there's an non-numeric character in the input so
atoll("123456abc890")
would return 123456
If you want to check each character by character, you could just use atoi on each character then reassemble the string for each character that passes.
http://www.cplusplus.com/reference/cstdlib/atoi/