comparing strings c++ with wildcard values - c++

I've been lurking around here for a long time, thank you for all your help in the past, even if this is the first question I've had to ask.
I'm trying to make a simple database program, and I am stuck the search requirement for it.
When searching, the user needs to be able to enter a question mark if they don't know a value. If you knew a movie was from the 90's you could enter 199? and it would find all the movies that matched 199_. I keep getting errors when I compile, "cannot convert 'char*' to 'char ()[5] for argument '2' to 'bool compareYears(const char, char (*)[5]"
I am trying to figure most of it out on my own, and I like to separate the functions and make them work in a separate .cpp file before adding them to the main file, just to make debugging easier.
#include <iostream>
#include <cstring>
#include <fstream>
#include <cctype>
using namespace std;
const int yearLength = 4;
typedef char year[yearLength + 1];
bool compareYears(const year year1, year year2[]);
int main()
{
year year1 = "1992"; //year from database, will be assigned the
// variable when implemented in main program.
year year2; //year entered by user, it will be compared to year1.
cout << "Enter a year to search for: ";
cin >> year2;
cout << endl;
if((compareYears(year1, year2)) == true)
cout << "they match\n";
if((compareYears(year1, year2)) == true)
cout << "they do not match\n";
return 0;
}
bool compareYears(const year year1, year year2[])
{
for(int i = 0; i < 4; i++)
{
if (strncom(year1, year2[i], 4) ==0)
return true;
else if (strncmp(year1, "????", 4) == 0)
return true;
else
return false;
}
}
Thanks for helping me out with this, usually the most help I get from others is useless or insulting. What I need help with most is getting rid of that compiler error. I cannot figure it out for the life of me.

First of all read this: typedef fixed length array
Then, use this typedef:
typedef struct year { char characters[4]; } year;
and change the code this way:
int main()
{
year year1;
year1.characters= "1992"; //year from database, will be assigned the variable when implemented in main program.
year year2; //year entered by user, it will be compared to year1.
cout << "Enter a year to search for: ";
cin >> year2.characters;
cout << endl;
if((compareYears(year1, year2)) == true)
cout << "they match\n";
else
cout << "they do not match\n";
return 0;
}
bool compareYears(year year1, year year2)
{
if (strncom(year1.characters, year2.characters, 4) ==0)
return true;
else if (strncmp(year1, "????", 4) == 0)
return true;
return false;
}
I also fixed some logical bugs

Just change these lines and it will work...the function declaration needs an array of year and you are trying to pass a variable..
if((compareYears(year1, &year2)) == true) //this changed from year2 to &year2
cout << "they match\n";
if((compareYears(year1, &year2)) == true) //this changed from year2 to &year2
cout << "they do not match\n";

The type of the year2 argument for compareYears looks strange. It looks like this argument is the mask to test against, i.e. a literal year like 1992 or something using wildcards. Hence, how about making it a char array of yearLength bytes?
It might be even easier to write just a generic function which is given two strings or arbitrary length (the second of which may use wildcards) and sees whether they are equal. The quality test could first see whether both strings are the same length and if so, whether the character at every position in both strings is either equal or the character at the given position in the second string is a '?'. You could use a single loop to walk over both strings in parallel to do this.

Related

How can I get an if-statement that takes multiple cin inputs to recognize an error if only the first cin input is incorrect?

I am building a program that is meant to store values from day-of-week/value pairs into a vector, and then display and sum the values for each day of the week. Therefore, I am asking the user to enter both a string (day of the week, which can be in 4 different forms for each day of the week) and an integer (a corresponding value) for each cin input. (The program only shows Monday and an exit condition so far; I will later build it out to include Tuesday through Sunday as well.)
The program is also meant to identify incorrect input (and allow the user to retry their input). However, I am having trouble getting the program to recognize erroneous input if only the day of week is entered incorrectly. For instance, the program will successfully announce "Incorrect day of week detected" if I enter "test test" as the input. It will also announce this message (even though the wording needs to be tweaked) if I enter "Monday x." However, if I enter "Test 5," the program accepts this without displaying the "Incorrect day of week" message.
How would it be possible to change my program so that, using the pre-existing else statement, it displays "Incorrect day of week" when I enter something like "Test 5"?
One solution would be to create a very long if statement that displays this message if the day of week entered does not match any of the 29 valid day-of-week entries (e.g. "Monday," "monday," "Mon," "mon," "Tuesday," "tuesday" . . . ). However, I would like to find a simpler approach.
Thank you for your help!
#include "../std_lib_facilities.h"
#include <iostream>
//Program in progress. Completing as part of my independent study of Programming: Principles and Practice by Bjarne Stroustrup.
int main()
{
string dayofweek;
int value;
vector<int> mondayvalues;
vector<int> tuesdayvalues;
vector<int> wednesdayvalues;
vector<int> thursdayvalues;
vector<int> fridayvalues;
vector<int> saturdayvalues;
vector<int> sundayvalues;
int incorrectentrycounter = 0;
int mondaysum = 0;
cout << "Please enter days of the week followed by values in integer form. When you are finished, please enter Done 0.\n";
string incorrectnumdump;
while (cin) {
if (cin >> dayofweek >> value) {
if (dayofweek == "Monday" || dayofweek == "monday" || dayofweek == "Mon" || dayofweek == "mon") {
mondayvalues.push_back(value);
}
if ((dayofweek == "Done") && (value == 0)) {
break;
}
}
else {
cin.clear();
cin >> incorrectnumdump;
cout << "Incorrect day of week detected; please try again.\n";
incorrectentrycounter++;
continue;
}
}
cout << "Here are the values you entered for each day of the week, along with their sums:\n";
cout << "Monday: ";
for (int x : mondayvalues)
cout << x << " ";
for (int i = 0; i < mondayvalues.size(); i++) {
mondaysum += mondayvalues[i];
}
cout << "\nSum of Monday values: " << mondaysum;
cout << "\nThere were " << incorrectentrycounter << "entries that displayed non-valid days of the week.";
}
Hmm.. Maybe you can use an ASCII technique to internally flip all inputs to either all caps or all small letters so that you won't have to look for both cases in your if statements as long as caps or small letters doesn't matter.
Make a function that takes the inputs and converts them to all caps or all small. Use this function before assigning the inputs to your variables. This will make checking them easier.
After that, you could create a const array[7] of std::string that will include all days. You can check your inputs by a method of elimination. You will be comparing input and array days letter by later and eliminating the days that don't match each time. If all days are eliminated then wrong input. If 2 or more days remain - input not sufficient. If 1 day remains that's the correct input!
Lemme know if you need help
After playing around with the code, I settled on this solution, which I think will meet my needs. The code now has two invalid entry statement blocks instead of one. The first ("Incorrect day of week detected") is within the if (cin >> dayofweek >> value) condition, and will identify dayofweek entries that don't match one of the Monday strings or Done.
The second ("Invalid entry") is outside the if (cin >> dayofweek >> value) condition but within the while (cin) condition. I added this second one so that if someone enters something like "test test," they will be notified of the error but the while loop will still continue.
So it seems as though when the user needs to enter multiple values via cin >>, one approach to input validation can be to enter multiple error messages at different levels of the code.
This solution is still a little clunky, but allows me to capture invalid entry with just "else" {} rather than "else" followed by a long set of conditions.
#include "../std_lib_facilities.h"
#include <iostream>
//Program in progress. Completing as part of my independent study of Programming: Principles and Practice by Bjarne Stroustrup.
int main()
{
string dayofweek;
int value;
vector<int> mondayvalues;
vector<int> tuesdayvalues;
vector<int> wednesdayvalues;
vector<int> thursdayvalues;
vector<int> fridayvalues;
vector<int> saturdayvalues;
vector<int> sundayvalues;
int incorrectentrycounter = 0;
int mondaysum = 0;
cout << "Please enter days of the week followed by values in integer form. When you are finished, please enter Done 0.\n";
string incorrectnumdump;
while (cin)
{
if (cin >> dayofweek >> value)
{
if (dayofweek == "Monday" || dayofweek == "monday" || dayofweek == "Mon" || dayofweek == "mon")
{
mondayvalues.push_back(value);
}
else if ((dayofweek == "Done") && (value == 0))
{
break;
}
else
{
cin.clear();
cin.ignore(10000, '\n');
cout << "Incorrect day of week detected; please try again.\n";
incorrectentrycounter++;
continue;
}
}
else
{
cin.clear();
cin.ignore(10000, '\n');
cout << "Invalid entry; please try again.\n";
incorrectentrycounter++;
continue;
}
}
cout << "Here are the values you entered for each day of the week, along with their sums:\n";
cout << "Monday: ";
for (int x : mondayvalues)
cout << x << " ";
for (int i = 0; i < mondayvalues.size(); i++)
{
mondaysum += mondayvalues[i];
}
cout << "\nSum of Monday values: " << mondaysum << "\n";
cout << "\nThere were " << incorrectentrycounter << " invalid entries.";
}

C++ Phone Number Program

I am new to this forum and am looking for some assistance, any help would be greatly appreciated! I am stuck on this assignment for my programming fundamentals 1 class and am desperate at this point as I have been stuck for hours on end. Thank you.
Here is the prompt:
Many websites ask for phone numbers. The problem is that there are so many
different ways to represent a phone number. Examples include 817-555-1234,
817 555 1234 (c), and (817) 555-1234 x23. Write a C++ program which inputs
a string containing a phone number in any format and outputs it in the standard
format. For this assignment, the standard format is (817)555-1234.
Your c++ program should:
1. Input a string including the number
2. Copy only the digits from the input string into another string
3. Issue an error message if the input string does not contain exactly 10
digits
4. Output the phone number in standard format
#include "stdafx.h"
#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <cctype>
using namespace std;
const int NUM_LENGTH = 10;
string ReadAndValidateUserNumber(string userNumber);
int main()
{
string userNumber;
ReadAndValidateUserNumber(userNumber);
system("PAUSE");
return 0;
}
string ReadAndValidateUserNumber(string userNumber)
{
bool check = false;
while (!check)
{
check = true;
cout << "Please enter a Number: ";
cin >> userNumber;
if (userNumber.length() != NUM_LENGTH)
cout << "The phone number may contain 10 digits only. \n";
else
{
userNumber.insert(0, "(");
userNumber.insert(4, ")");
userNumber.insert(8, "-");
for (int i = 0; i < userNumber.length(); i++)
{
if (isdigit(userNumber[i]))
{
userNumber = NUM_LENGTH;
}
}
}
if (!check)
{
cout << "Invalid Entry! Please try again." << endl;
}
}
return userNumber;
}
You appear to have a logic error.
bool check = false;
while (!check)
{
check = true;
....
if (!check)
{
cout << "Invalid Entry! Please try again." << endl;
}
}
You'll note check never becomes false again. Hence the bottom if statement will never execute and the loop will never iterate more than once as check is always true. You probably want to make
check = true
conditional on the correct format being entered.
The code is in a horrible state. Calm down and focus. There are many problems aside from what you've written. I recommend you to carry the working code to any code reviewing site.
You're doing the check incorrectly, as well as what you're doing after the check is wrong as well.
userNumber = NUM_LENGTH;
This will truncate NUM_LENGTH into char, so you'll have something strange inside userNumber.
This is the right check:
if (!isdigit(userNumber[i]))
{
std::cout << "input should be only numbers\n";
return; //function should return void
}
^^ this is what you should do if you want to break on non number input, if you want to skip non digits, you can use std::copy_if into another string, or tweak the above thing to do it for you. You can also use std::remove_if if you want to remove the non number stuff.
std::string fetched_input;
std::copy_if(userNumber.begin(), userNumber.end(), fetched_input.begin(), std::isdigit);
^^ this will give you the string only with numbers.
Also, you're not doing the check in the correct place. Think about it again.

Receiving a string, checking for a Capital Letter

What Im trying to do is check if the user-supplied string has a capital letter or not.
The first part of the code with the enumerated constant, is just there for another method,
which I got to work using numbers assigned to the words Sunday = 7, Monday=1, Tuesday=2, etc. I'm trying have the user not supply numbers, but the actual word (Sunday, Monday, Tuesday), but I want them to specify the day of the week with a capital letter.
Problem I get: compiles fine, but anything you type in is somehow redirected along an execution path that always returns "Retype w/ a capital letter." This happens if I type in fjdkalfda or sunday or Sunday or whatever. Here is the code. Sorry if its not in code format, first time user of Stack Overflow.
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main(){
/*enum DaysOfWeek {
Monday = 1,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};*/ //I'm not using this, but I can get my code to work with this
//enumerated constant by asking the user to input a number corresponding
//to the day of the week and then using if-else statements to check, say,
// int Day;
// cin >> Day
// then use if statements to check if Day = a certain number, to give output
cout << "Enter the day of week with a capital letter: ";
string Day;
getline(cin, Day);
if (Day == ("monday") || ("tuesday"))
cout << "Retype w/ a capital letter" << endl;
else if (Day == ("wednesday") || ("thursday"))
cout << "Retype w/ a capital letter" << endl;
else if (Day == ("friday") || ("saturday"))
cout << "Retype w/ a capital letter" << endl;
else if (Day == ("sunday"))
cout << "Retype w/ a capital letter" << endl;
else
{
if (Day == "Monday")
cout << "Moon" << endl;
else if (Day == "Tuesday")
cout << "Mars" << endl; //continue with the days etc...
}
return 0;
}
One would observe that there is a function called toupper which can turn a lower case letter into upper case, and leave an upper case letter alone. Perhaps you can reuse this function to help solve your problem with less code.
I am inferring from your code that you are only interested in verifying that the first letter is a capital letter. Is that correct?
There is an isupper function in ctype.h that returns true if a char is upper case:
#include <ctype.h>
...
isCapitalized = isupper(str[0]);
...
I'm assuming you're actually not bothered about capitol letters if we can somehow organize the input choice in an enum type. Instead of this enum classes would be a better choice if you have C++11. If not, it would be quite easy to change this code for normal enums
If you're using gcc/g++, you may need to include prefix -std=c++11
Note: you may want to add another enum element to enum class Days such as null_day. Or even better, Make sure user inputs the correct day, until he/she does, don't carry on with program (hint: use while loop when using getline)
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
using std::string;
using std::transform;
using std::cout;
using std::cin;
using std::endl;
// only in C++ 11
enum class Day {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
int main () {
cout << "Enter the day of week: ";
// store day from user input, transform all to lower case so
// we don't bother with user input type (only error in spelling will be the problem now)
string get_day;
getline(cin, get_day);
transform(get_day.begin(), get_day.end(), get_day.begin(), tolower);
// define instance of enum class Day, and sort out what day user has input
// note that if you do not initialize myDay object, it will set to the first
// element in the enum class Day above (which is Monday). This will happen
// if user input is not allowed to initialize it. See the << >> section below
Day myDay;
if (get_day == "monday")
myDay = Day::Monday;
else if (get_day == "tuesday")
myDay = Day::Tuesday;
else if (get_day == "wednesday")
myDay = Day::Wednesday;
else if (get_day == "thursday")
myDay = Day::Thursday;
else if (get_day == "friday")
myDay = Day::Friday;
else if (get_day == "saturday")
myDay = Day::Saturday;
else if (get_day == "sunday")
myDay = Day::Sunday;
else
<< ERROR CODE HERE >>
<< MAYBE A WHILE LOOP UNTIL USER INPUTS CORRECT DATA >>
// perform your calculations/operations/etc separate from above
if (myDay == Day::Monday)
cout << "Moon" << endl;
else if (myDay == Day::Tuesday)
cout << "Mars" << endl; //continue with the days etc...
return 0;
}

Palindrome tester has logic flaws

This is just a basic palindrome tester for my C++ class, and there appears to be issues.
I already know that I have two separate flaws in here somewhere. At least one, I strongly suspect, is a logic issue. The first problem is that it runs fine the first time through, but when the loop initiates, it doesn't ask for user input to put in a new line to test as a palindrome, it simply retests the old one. The second issue is, I assume, that it is testing spaces, which I base off the fact that it's giving 'hannah' back as good, but 'never even or odd' comes back bad. This one I just don't know how to fix.
#include <iostream>
#include <string>
using namespace std;
int main()
{
bool repeater = true;
do
{
string palindroneCheck;
bool palindronity = true;
cout << "Please enter a line to test for palindromity.\n";
getline(cin, palindroneCheck);
int stringSize = palindroneCheck.size();
int cutOff = stringSize/2;
for (int palindroneLength = 0; palindroneLength < cutOff; palindroneLength++)
{
if (palindroneCheck[palindroneLength] != palindroneCheck[stringSize - palindroneLength -1])
{palindronity = false;
break;}
}
if(palindronity == true)
cout << "Congratulations! This line is a palindrone!\n\n";
else
cout << "Sorry, but this is not a palindrone.\n\n";
palindroneCheck.clear();
char repeat;
cout << "Would you like to try another line? Y/N\n";
cin >> repeat;
if (repeat == "n" || repeat == "N")
repeater = false;
} while (repeater == true);
}
OK, you are right about the spaces. Your code will demand that spaces are in the same location like every other character.
The other bug seems more subtle: it's where you ask to repeat or not.
Why? Because it asks, you enter 'n' and then 'enter'
The cin >> repeat only reads the 'n', but not the 'enter'
so the next time you do `readline(cin,PalindromCheck)' it will read an empty string.
Try to write palindromCheck just after reading it. You'll see.
The reading issue of getline is solved by comments. For the whitespaces, you can tackle it by removing all the spaces inside string palindroneCheck,
std::string::iterator new_end = std::remove(palindroneCheck.begin(), palindroneCheck.end(), ' ');
std::string palindroneCheckWithoutSpaces(palindroneCheck.begin(), new_end);
Then you use palindroneCheckWithoutSpaces to do the Palindrone test.
int stringSize = palindroneCheckWithoutSpaces.size();
int cutOff = stringSize/2;
for (int palindroneLength = 0; palindroneLength < cutOff; palindroneLength++)
{
if (palindroneCheckWithoutSpaces[palindroneLength] != palindroneCheck[stringSize - palindroneLength -1])
{palindronity = false;
break;}
}
if(palindronity == true)
cout << "Congratulations! This line is a palindrone!\n\n";
else
cout << "Sorry, but this is not a palindrone.\n\n";
(you need header algorithm to use remove)
Update:
std::remove remove an element from the input range (this is defined by begin and end here) based on the value you passed in , here is the whitespace ' '. Then it return the new end of the changed range (since you delete something, the range becomes smaller). The new range starts with begin and ends with the returned value.
So the second line you create a new string based on the new range.

Comparison with string literal results in unspecified behaviour?

I am having a problem with the program I am trying to code. It's just a Windows console program and I am very new to C++. It's only my 4th program.
The problem I am having is that when I run my program I have no errors but a lot of warnings that say "comparison with string literal results in unspecified behaviour" in the lines that I will highlight below.
When the program runs instead of adding the numbers I want it to it just gives me a random huge number no matter what I put in for my inputs.
Here is the code:
#include <iostream>
using namespace std;
int main()
{
int hold;
int i;
int n;
i = 6;
int result;
int * price;
char items[100][100];
if (items == 0)
cout << "No items can be stored";
else
{
for (n=0; n<i; n++)
{
cout << "Item#" << n << ": ";
cin >> items[n];
}
cout << "\nYou Entered: \n";
for (n=0; n<i; n++)
cout << items[n] << ", ";
}
for (n=0; n<i; n++)
{
if (items[n] == "ab"){
price[n] = 2650;
}
else if (items[n] == "ae"){
price[n] = 1925;
}
else if (items[n] == "ie"){
price[n] = 3850;
}
else if (items[n] == "bt"){
price[n] = 3000;
}
else if (items[n] == "pd"){
price[n] = 2850;
}
else if (items[n] == "ga"){
price[n] = 2600;
}
}
for (n=0; n<i; n++)
{
result = result + price[n];
}
cout << "\nTotal gold for this build: " << result;
cin >> hold;
return 0;
}
Any help is appreciated. There is probably something big that I've done wrong. The names in the if statements are all currently placeholders and I'll be adding a lot more if statements when I can get it to work with the bare 6 which is what it needs to work.
In C++ == only implemented internally for primitive types and array is not a primitive type, so comparing char[100] and string literal will only compare them as 2 char* or better to say as 2 pointers and since this 2 pointers can't be equal then items[n] == "ae" can never be true, instead of this you should either use std::string to hold string as:
std::string items[100];
// initialize items
if( items[n] == "ae" ) ...
or you should use strcmp to compare strings, but remeber strcmp return 0 for equal strings, so your code will be as:
char items[100][100];
// initialize items
if( strcmp(items[n], "ae") == 0 ) ...
And one extra note is if (items == 0) is useless, since items allocated on stack and not in the heap!
First, int * price; is a dangling pointer - you never initialize it. You have to do:
int * price = new int[i];
Second, usually, i denotes an iterator index so I suggest you stick with that - so
for (i=0; i<n; i++) //some more refactoring needed
Third, you need to compare char arrays using strncmp in your case.
Fourth and most important - use std::string and std::vector instead. This is C++, not C.
Just a little thing that got me stumbling for a bit, is the difference between single and double quotes, see: Single quotes vs. double quotes in C or C++
I was comparing the first character of a string with double quotes and not single quotes - which resulted in above's error message.
You're comparing pointers, not the actual strings. Use C++ string class instead of char* (or check how C strings work).