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.
Related
Okay, So I've looked around on StackOverflow and I've stumbled across a way of splitting C++ via delimiters.
So far, I've looked at these, and I still don't understand it.
Parse (split) a string in C++ using string delimiter (standard C++)
https://www.oreilly.com/library/view/c-cookbook/0596007612/ch04s07.html
C++ spliting string by delimiters and keeping the delimiters in result
split a C++ string into two integers, which are delimited by ":"
From my understanding, I need to use a delimiter, using a variable that houses the delimiter, and then use the substr() method/function, but I don't understand the whole thing.
For instance, I saw this one example where it was referencing pos and npos, I don't understand that. And my other issue is, I wouldn't know how to do it with a string with multiple copies of the same delimiter.
My goal is to take a date like this: "29/01/2022 • 05:25:01" to split it into a struct for date and time, eg:
struct Date
{
int day; //Integer for days
int month; //Integer for months
int year; //Integer for years
};
struct Time
{
int hour; //Integer for hour of drop
int minute; //Integer for minute of drop
int second; //Integer for second of drop
int milisecond; //Integer for milisecond of drop
};
I've also looked at https://www.cplusplus.com/reference/, however I want to split it up so that they are stored in their own variables, eg:
string example
{
struct Date D;
struct Time T;
D.Day = 29;
D.Month = 01;
D.Year = 2022;
T.Hour = 5;
T.Minute = 25;
T.Second = 01;
}
Would someone be able to explain this to me in a simpler way, or show me a source that explains it easier? The main problem I have is not understanding certain words.
Any help is appreciated, I really am trying to learn, but I don't quite understand these subjects yet.
Let's go step by step, starting with the date:
29/01/2022 -- Day, Month, Year.
Given the following:
unsigned int day = 0u;
std::cin >> day;
The input of an integer skips whitespace until the first number character (for the first number character, also includes '+' and '-'). The extraction operator keeps reading characters, building a number, until a non-numeric character is reached:
2 --> day.
9 --> day.
The next character is '/', which is not a numeric character so the extraction operator returns the number 29.
The character '/' in this context is known as a delimiter, because it separates the day field from the month field.
Since it's a character, it has to be read using a character variable:
char delimiter = '\0';
std::cin >> delimiter;
Now, the delimiter is no longer in the buffer.
You can check the content of the delimiter variable or move on.
Reading the month is similar:
unsigned int month = 0U;
std::cin >> month;
Edit 1: delimiter and substrings
You could extract the month as a string using a delimiter:
std::string month_as_text;
std::getline(std::cin, month_as_text, '/');
The getline function above reads characters from std::cin, placing into the string month_as_text, until it finds the delimiter character '/'. You can then convert month_as_text into an integer variable.
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'm currently learning through Bjarne Stroustrup's book "Programming: Principles and Practice Using C++".
I'm at the point where we try to concatenate strings using the following example (edited for the actual code as requested):
I apologize I failed to mention that the program works. But whenever I type both names it shows blank.
#include "std_lib_facilities.h"
int main()
{
string first;
string second;
string name = first + ' ' + second;
cout << "Please enter your first and second names\n";
cin >> first >> second;
cout << "Hello, "<<name<<'\n';
}
I just want to mention that this is not the way it was written in the book. I just wanted to play with different setups such as putting all the string variables in one area together. However, I found out that String name = first + ' ' +second; does not work unless I put it after the cin >> first >> second; line.
Is there an explanation for this?
Reference code from the book:
int main ()
{
cout<<"Please enter your first and second name\n";
string first;
string second;
cin>>first>>second;
string name=first +' '+second;
cout<< Hello, "<<name<<'\n';
}
I mean it probably did work. The problem here is that the result isn't what you think it is.
Strings are usually empty by default. So an empty string + a space + another empty string = just a space. It's highly likely you're seeing this space, but it looks empty because spaces are, well, spaces.
If you want to concatenate the input from the user, you will have to do so after you capture that input as the program has no other way to know what the user inputted otherwise.
If you're still confused, I'm afraid I unfortunately don't know what else to tell you other than that's just the way C++ works.
I would suggest looking more into what a variable is and what cin does. A variable holds a value. cin retrieves input from a user and puts it into a variable. Of course adding two variables with no value will not work as if there were values there. Instead, you are adding two blank strings to a space.
Also, when you do:
string name=first +' '+second;
You are setting name to the value of first plus the value of ' ' plus the value of second. The variable is not a reference to those values. Meaning that changing first and second after this point does not affect the value of the 'name' variable.
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/
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]))+))+