How to arrange the loops to check for numbers - c++

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/

Related

how to ignore n integers from input

I am trying to read the last integer from an input such as-
100 121 13 ... 7 11 81
I'm only interested in the last integer and hence want to ignore all
previous integers.
I thought of using cin.ignore but that won't work here due to
unknown integers (100 is of 3 digits, while 13 is of 2 digits & so on)
I can input integer by integer using a loop and do nothing with them. Is there a better way?
It all depends on the use case that you have.
Reading a none specified number of integers from std::cin is not as easy at it may seem. Because, in contrast to reading from a file, you will not have an EOF condition. If you would read from a file stream, then it would be very simple.
int value{};
while (fileStream >> value)
;
If you are using std::cin you could try pressing CTRL-D or CTRL-Z or whatever works on your terminal to produce an EOF (End Of File) condition. But usually the approach is to use std::getline to read a complete line until the user presses enter, then put this line into a std::istringstream and extract from there.
Insofar, one answer given below is not that good.
So, next solution:
std::string line{};
std::getline(std::cin, line);
std::istringstream iss{line};
int value{};
while (iss >> value)
;
You were asking
Is there a better way?
That also depends a little. If you are just reading some integers, then please go with above approach. If you would have many many values, then you would maybe waste time by unnecessarily converting many substrings to integers and loose time.
Then, it would be better, to first read the complete string, then use rfind to find the last space in the string and use std::stoi to convert the last substring to an integer.
Caveat: In this case you must be sure (or check with more lines of code) that there are no white space at the end and the last substring is really a number. That is a lot of string/character fiddling, which can most probably avoided.
So, I would recommend the getline-stringstream approach.
You can try this simple solution for dynamically ignoring rest of the values except the last given in this problem as shown:
int count = 0;
int values, lastValue; // lastValue used for future use
std::cout << "Enter your input: ";
while (std::cin >> values) {
lastValue = values; // must be used, otherwise values = 0 when loop ends
count++;
}
std::cout << lastValue; // prints
Note: A character must be required to stop the while(), hence it's better put a . at last.
Output example
Enter your input: 3 2 4 5 6 7.
7
Try this:
for( int i=0; i<nums_to_ignore; i++) {
int ignored;
std::cin >> ignored;
}

How can i limit the input the number of decimals till which user can input value?

For Eg. Accept 4.55324 as the user input and reject if 6.22356 is entered, i.e accept till 5 decimal places.
The easiest way to do this is to read the input as a string, check that it matches you desired format, and only then convert it to a number. For example, using the C++11 regex feature for validation:
double number;
std::string input;
std::cin >> input;
std::regex pattern ("^[-+]?[0-9]+(\.[0-9]{1,5})?$");
if (std::regex_match(input, pattern)) {
number = std::stod(input);
}
else {
// handle invalid input here
}
Note that the regex above is fairly strict: it accepts 12, 012, +12.3, -12.34567 and 0.12345, but rejects 12., .5, 0.123450 and 1.2e2. You may wish to tweak it to match your specific format requirements (whatever they may be).
You could read a line as a string using std::getline then parse that string according to your needs (and finally convert it to a double perhaps using atof on its c_str() or preferably std::stof...)
Your examples are not precise enough: should you accept 453.210e-3 or 0.1234567e+3 etc.
You really should read http://floating-point-gui.de/ (I believe your requirements are next to useless)

Taking inputs if number of inputs is not known

I wish to take inputs from console where the number of inputs are not known. All i know is that they are less then or equal to 10.
I wrote this code but it evaluates the last value twice.
int x;
do{
cin>>x;
cout<<check(x)<<"\n";
}while(std::cin);
The inputs are in this form:
12
2
45
As #LightnessRacesinOrbit commented, it's while(!eof) bug again. You should check the stream state after reading from it, not before.
You can use cin>>x in the while-condition and apply a special value (i.e. anything not a number) as the end flag like this:
while (cin >> x)
{
// got a value
}
You may use istream::geline.
char input[1024]
std::cin.getline (input,1024);
After you read the line, you have to split it by white-spaces as delimiter. Just ignore 11th split onwards. And you may apply atoi or similar functions on the splits (some_split.c_str()) to get the numeric values

C++ string parsing

All:
I got one question in string parsing:
For now, if I have a string like "+12+400-500+2:+13-50-510+20-66+20:"
How can I do like calculate total sum of each segment( : can be consider as end of one segment). For now, what I can figure out is only use for to loop through and check +/- sign, but I do not think it is good for a Universal method to solve this kind of problem :(
For example, the first segment, +12+400-500+2 = -86, and the second segment is
+13-50-510+20-66+20 = -573
1) The number of operand is varied( but they are always integer)
2) The number of segment is varied
3) I need do it in C++ or C.
I do not really think it as a very simple question to most newbie, and also I will claim this is not a homework. :)
best,
Since the string ends in a colon, it is easy to use find and substr to separate out parts of the string partitioned by ':', like this:
string all("+12+400-500+2:+13-50-510+20-66+20:");
int pos = 0;
for (;;) {
int next = all.find(':', pos);
if (next == string::npos) break;
string expr(all.substr(pos, (next-pos)+1));
cout << expr << endl;
pos = next+1;
}
This splits the original string into parts
+12+400-500+2:
and
+13-50-510+20-66+20:
Since istreams take leading plus as well as leading minus, you can parse out the numbers using >> operator:
istringstream iss(expr);
while (iss) {
int n;
iss >> n;
cout << n << endl;
}
With these two parts in hand, you can easily total up the individual numbers, and produce the desired output. Here is a quick demo.
You need to seperate operands and operators. To do this you can use two queue data types one for operands and one for operators
split by :, then by +, then by -. translate into int and there you are.
Your expression language seems regular: you could use a regex library - like boost::regex - to match the numbers, the signs, and the segments in groups directly, with something like
((([+-])([0-9]+))+)(:((([+-])([0-9]))+))+

Validation of string and date input in c++?

I just started c++ today. I am doing some simple registration program. I want to validate the input. I got stuck when validate fullname and birth_date. Here is my requirements:
Fullname: I just want to check if its empty and no punctuation
date_birth: i know this is abit tricky. But if I could validate if the input is valid like: month(1-12), date(1-30) and year (not more than current year) should be enough.
Any quick way to do this?
EDIT:
I tried googled string validation, i am still getting lots of errors. Here is my current code:
string fullname;
do{
cout << endl << "Please enter your fullname";
cin >> fullname;
} while(!ispunct(fullname));
My error message is:
XXXX: no matching function for call to `ispunct(std::string&)'
I already include the library, is this a correct way to check string input. How do you usually do the validation?
EDIT 2:
bool valid;
string fullname;
do{
valid = true;
cout << endl << "Please enter your fullname";
cin >> fullname;
string::iterator it;
for ( it=fullname.begin() ; it < fullname.end(); it++ )
if(ispunct(*it)){
valid = false;
}
} while(!ispunct(fullname));
Its weird, I entered: "!!!", it still by pass. Something is wrong in my code?
Well, I'll try to steer you in the right direction. Firstly, in order to validate the string, you'll need to iterate over it character by character. You can do this using iterators and a for loop. The string class has a begin() and end() method, which you can use to loop over the whole string and examine each character.
Once you're looping over the string, all you need to do is write code to validate it based on your requirements. To make sure there's no punctuation characters, you can use the std::ispunct function, which will tell you whether or not a character is a punctuation character. If you find any punctuation characters, simply consider it an error.
Your first requirement, checking whether the string is empty, is trivial. The string class has an empty() method which returns true if the string is empty.
Validating the birthday is more tricky. This is the sort of thing regular expressions were made for. Unfortunately, C++ has no built-in support for regular expressions (at least not until the next version of the standard). If you're interested, Boost has a good regular expression library in the meantime.
Otherwise, you'll need to loop over the string and validate each character. Make sure the string starts with characters that form a word corresponding to a month name, then make sure a parenthesis falls after that, etc. You'll need to decide how to handle white spaces in between characters. This will be tricky, but it's a good practice exercise to become familiar with C++.
Solution for the second requirement can be trivial if you choose different data type to represent date of birth. Constraints you mentioned here are all numeric (1<= day <= 31, 1 <= month <= 12, 1900 <= year <=2010) and date of birth is basically a set of three numbers so consider using struct type for birth_date variable, something like this:
struct Date{
unsigned int day;
unsigned int month;
unsigned int year;
};
Date birth_date = {3, 12, 1983};
When you pass birth_date to function that performs validation, you just need to compare struct members against limits.