input string validation without external libraries for c++ - c++

I need to validate one input string from a user. Eventually it will need to break down into two coordinates. ie a4 c3. And once they are coordinates they need to be broken out into 4 separate ints. a=0 b=1, etc. They must also follow the following stipulations:
If an end-of-input signal is reached the program quits.
Otherwise, all non-alphanumeric characters are discarded from the input.
If what remains is the single letter 'Q'
Then the program quits.
If what remains consists of 4 characters, with one letter and one digit among the first two characters and one letter and one digit among the last two characters, and if each letter-digit pair is in the legal range for our grid
Then input is acceptable.
I have completely over-thought and ruined my function. Please let me know where I can make some corrections.
I am mainly having trouble going from one string, to four chars if and only if the data is valid. Everything else I can handle.
Here is what I have so far.
void Grid::playerMove()
{
string rawMove;
string pair1 = " ";
string pair2 = " ";
bool goodInput = false;
char maxChar = 'a';
char chary1, chary2;
int x11,x22,y11,y22;
for (int i =0; i<size; i++)
{
maxChar++;
}
while(!goodInput)
{
cout<<"What two dots would you like to connect? (Q to quit) ";
cin>>rawMove;
rawMove = reduceWords(rawMove);
if (rawMove == "Q")
{
cout<<"end game";
goodInput = false;
}
else if (rawMove.size() == 4)
{
for(int j=0;j<2;j++)
{
if (pair1[j] >='a' && pair1[j] <=maxChar)
{
chary1 = pair1[j];
}
else if(pair1[j] >=0 && pairl[j]<=size+1)
{
x1 = pair1[j];
}
}
for(int k=0;k<2;k++)
{
if (pair2[k] >='a' && pair2[k] <=maxChar)
{
chary2 = pair2[k];
}
else if(pair2[k] >=0 && pair2[k]<=size+1)
{
x2 = pair2[k];
}
}
}
if(char1 != NULL && char2 != NULL && x1 !=NULL && x2 != NULL)
{
for (int m = 0; m <= size m++)
{
if (char1 == m;)
{
x1 = m;
}
}
for (int n = 0; n <= size n++)
{
if (char2 == n)
{
x2 = n;
}
}
}
}
The end goal would be to have x1, x2, y1, and y2 with their respective values.
Keep in mind I am not allowed to have any external libraries.

It's not clear what exactly you want to achieve, but here are some pointers to get you started:
The while loop will never end because you're setting goodInput to false on quit which lets the loop continue.
The code probably does not even compile? You are missing a curly closing brace..
You are initializing pair1 and pair2 to empty strings but never change them again, so they will never contain any real information about your moves
maybe what you really want is to split up rawMove into the pair1 and pair2 substrings first?

Since this is a homework - and you're supposed to learn from those (right?) - I'm not going to give you the complete answer, but rather something like a recipe:
Use std::istream::getline(char*, std::streamsize s) to read a whole line from std::cin. Make sure you allocate a buffer large enough to hold the expected input (including the terminating null character) plus some more for invalid characters. After the call, check the failbit (input was too long) and the eofbit (hit the end-of-input) of the std::cin stream and handle those cases. Construct a std::string from the buffer if there was no error or EOF has not been reached.
Write a character-classification function (e.g. call it isAlNum(char c)) that returns true if the char argument is alpha-numeric, and false otherwise.
Combine std::string::erase(), std::remove_if(), std::not1(), std::ptr_fun() and your function isAlNum() to sanitise the input string.
Write a function that validates and parses the coordinates from the sanitised input string and call it with the sanitised input string.
Wrap the whole thing in an appropriate while() loop.
This should get you started in the right direction. Of course, if you're allowed to use C++11 features and you know how to write good regular expressions, by all means, use the <regex> header instead of doing the parsing manually.

Related

Simple Word Guessing Game

bool guess(char c)
{
if (guesses[c])
{
guesses[] = c;
return true;
}
else if (c > ='a' && c <= 'z')
{
guesses[] = c;
return false;
}
}
bool guesses[255] = {};
I need to use this to see if the person has enter a char between a - z and if they haven't I return true else I will return false. either way I will also update guesses with the char. Right now I don't understand how to add char to the array, so that next time I check the it will be false and tell them it was already guessed. I understand this is using the ASCII table but beyond that I am lost. Could anyone explain why this won't work.
I currently get the error
expected primary-expression before']'
but if I take bracket out I get
incompatible type char to bool
which make sense but then how do I make it so where char c is will be mark true in the Boolean array
You've left your brackets empty, so you currently aren't providing an index:
guesses[c] = c;
But you also don't want to assign the char to guesses, you'd want to assign a bool:
guesses[c] = true;
That will compile* and fix your problem.
* Note you also have a syntax error with > =, which I assume was just a copy+paste issue from the editor to the question, but you should fix that also to be >=. Your function guess can also potentially not return (if neither the if or else if are true), which is undefined behaviour. You should ensure all control paths return a value, and you should make sure you compile at the highest warning level so you are warned about these things.
But not your design.
Since you're only dealing with characters a-z, you don't need to allocate all 255 elements like you do. You could simply minus the character to obtain the correct index:
bool guesses[26];
if (c >='a' && c <= 'z')
guesses[c-'a'] = true;
Consider instead using a std::set, a container of unique elements, to track whether a character has been pressed:
#include <set>
std::set<char> guesses;
bool guess(char c)
{
// Have we already inserted this character?
if (guesses.find(c) != std::end(guesses))
{
// Character has already been guessed:
std::cout << "This character has already been guessed";
return true;
}
else if (c >= 'a' && c <= 'z')
{
// Valid guess:
guesses.insert(c);
return false;
}
}

check if one string is interleaved by two other strings

I am debugging the following problem. Post detailed problem statement and the coding. My question is whether the last else if (else if (A[i-1]==C[i+j-1] && B[j-1]==C[i+j-1])) is necessary? I think it is not necessary since it is always covered either by else if(A[i-1]==C[i+j-1] && B[j-1]!=C[i+j-1]), or covered by else if (A[i-1]!=C[i+j-1] && B[j-1]==C[i+j-1]), i.e. previous two if-else check conditions. Thanks.
Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 = "aabcc",
s2 = "dbbca",
When s3 = "aadbbcbcac", return true.
When s3 = "aadbbbaccc", return false.
// The main function that returns true if C is
// an interleaving of A and B, otherwise false.
bool isInterleaved(char* A, char* B, char* C)
{
// Find lengths of the two strings
int M = strlen(A), N = strlen(B);
// Let us create a 2D table to store solutions of
// subproblems. C[i][j] will be true if C[0..i+j-1]
// is an interleaving of A[0..i-1] and B[0..j-1].
bool IL[M+1][N+1];
memset(IL, 0, sizeof(IL)); // Initialize all values as false.
// C can be an interleaving of A and B only of sum
// of lengths of A & B is equal to length of C.
if ((M+N) != strlen(C))
return false;
// Process all characters of A and B
for (int i=0; i<=M; ++i)
{
for (int j=0; j<=N; ++j)
{
// two empty strings have an empty string
// as interleaving
if (i==0 && j==0)
IL[i][j] = true;
// A is empty
else if (i==0 && B[j-1]==C[j-1])
IL[i][j] = IL[i][j-1];
// B is empty
else if (j==0 && A[i-1]==C[i-1])
IL[i][j] = IL[i-1][j];
// Current character of C matches with current character of A,
// but doesn't match with current character of B
else if(A[i-1]==C[i+j-1] && B[j-1]!=C[i+j-1])
IL[i][j] = IL[i-1][j];
// Current character of C matches with current character of B,
// but doesn't match with current character of A
else if (A[i-1]!=C[i+j-1] && B[j-1]==C[i+j-1])
IL[i][j] = IL[i][j-1];
// Current character of C matches with that of both A and B
else if (A[i-1]==C[i+j-1] && B[j-1]==C[i+j-1])
IL[i][j]=(IL[i-1][j] || IL[i][j-1]) ;
}
}
return IL[M][N];
}
thanks in advance,
Lin
You do need the final else if to catch the cases when the next character in C matches the next character in both A and B. For example, run your program with A="aaaa", B="aaaa", and C="aaaaaaaa" and see if you enter that last else if block.
Additionally, you also need a final else block to handle cases when none of the previous conditions match. In this case, you need to set IL[i][j] to false. Otherwise, the function will incorrectly return true.
Edit: Even though the code uses memset to initialize all elements of IL to 0, it may not work because ISO C++ does not support variable length arrays (VLAs). In fact, this is what happened when I tried the code at cpp.sh. It uses g++-4.9.2 with flags that causes it to report sizeof(IL) to be 1 even though g++ is supposed to support VLAs. Maybe this is a compiler bug or maybe it does not support multidimensional VLAs. In any case, it might be safer to not use them at all.

iterating vector of strings C++

The code is to read instructions from text file and print out graphic patterns. One is my function is not working properly. The function is to read the vectors of strings I've got from the file into structs.
Below is my output, and my second, third, and sixth graphs are wrong. It seems like the 2nd and 3rd vectors are not putting the correct row and column numbers; and the last one skipped "e" in the alphabetical order.
I tried to debug many times and still can't find the problem.
typedef struct Pattern{
int rowNum;
int colNum;
char token;
bool isTriangular;
bool isOuter;
}Pattern;
void CommandProcessing(vector<string>& , Pattern& );
int main()
{
for (int i = 0; i < command.size(); i++)
{
Pattern characters;
CommandProcessing(command[i], characters);
}
system("pause");
return 0;
}
void CommandProcessing(vector<string>& c1, Pattern& a1)
{
reverse(c1.begin(), c1.end());
string str=" ";
for (int j = 0; j < c1.size(); j++)
{
bool foundAlpha = find(c1.begin(), c1.end(), "alphabetical") != c1.end();
bool foundAll = find(c1.begin(), c1.end(), "all") != c1.end();
a1.isTriangular = find(c1.begin(), c1.end(), "triangular") != c1.end() ? true : false;
a1.isOuter = find(c1.begin(), c1.end(), "outer") != c1.end() ? true : false;
if (foundAlpha ==false && foundAll == false){
a1.token = '*';
}
//if (c1[0] == "go"){
else if (c1[j] == "rows"){
str = c1[++j];
a1.rowNum = atoi(str.c_str());
j--;
}
else if (c1[j] == "columns"){
str = c1[++j];
a1.colNum = atoi(str.c_str());
j--;
}
else if (c1[j] == "alphabetical")
a1.token = 0;
else if (c1[j] == "all"){
str = c1[--j];
a1.token = *str.c_str();
j++;
}
}
}
Before debugging (or posting) your code, you should try to make it cleaner. It contains many strange / unnecessary parts, making your code harder to understand (and resulting in the buggy behaviour you just described).
For example, you have an if in the beginning:
if (foundAlpha ==false && foundAll == false){
If there is no alpha and all command, this will be always true, for the entire length of your loop, and the other commands are all placed in else if statements. They won't be executed.
Because of this, in your second and third example, no commands will be read, except the isTriangular and isOuter flags.
Instead of a mixed structure like this, consider the following changes:
add a default constructor to your Pattern struct, initializing its members. For example if you initialize token to *, you can remove that if, and even the two bool variables required for it.
Do the parsing in one way, consistently - the easiest would be moving your triangular and outer bool to the same if structure as the others. (or if you really want to keep this find lookup, move them before the for loop - you only have to set them once!)
Do not modify your loop variable ever, it's an error magnet! Okay, there are some rare exceptions for this rule, but this is not one of them.
Instead of str = c1[++j];, and decrementing later, you could just write str = c1[j+1]
Also, are you sure you need that reverse? That makes your relative +/-1 indexing unclear. For example, the c1[j+1 is j-1 in the original command string.
About the last one: that's probably a bug in your outer printing code, which you didn't post.

Inexistent double decrement?

I was writing a little game, where there is an hidden word, and the user must guess, char to char, what word is.
While coding this I got stucked in something that I don't understeand where and how it happens.
while(true)
{
if(Hue == 0)
Try -= 1;
if(Hue == 1)
Hue = 0;
GotoXY(0, 3);
printf("Inserisci una lettera maiuscola\n>");
GotoXY(1, 4);
scanf("%c", &Key);
GotoXY(0, 4);
printf(" ");
GotoXY(0, 6);
printf("Numero di tentativi rimasti: %d ", Try);
for(unsigned short Iterator = 1; Iterator < Length - 1; ++Iterator)
if(Key == UserString[Iterator])
{
for(unsigned short SecIterator = Iterator; SecIterator < Length - 1; ++SecIterator)
{
if(Key == UserString[SecIterator])
{
GotoXY(SecIterator, 1);
printf("%c", Key);
}
}
Hue = 1;
break;
}
}
Hue is a simple control variable to check if the key was in the word.
If it's still 0 then the key wasn't in the word, so the Try decrements it self and so on.
But what happen is that Hue, either is 0 or 1 causes the decrement of Try, and the thing even more stange is that Try decrement twice when is 0, evenly in the code isn't written nothing like that.
Thanks for the help.
It seems the confusion is mostly due to the double decrement: well, you are reading chars and most likely you hit return making two chars available: the entered character and the '\n' from the return. Since apparently neither character matches you get two decrements.
Just for a bit of explanation: when using the formatted input using std::cin >> Key leading whitespace is skipped. When using scanf("%c", &c) each character is extracted. I think you can have scanf() skip leading spaces using
if (1 == scanf(" %c", &c)) {
// process the input
}
Note the extra space in front of the '%c'. To debug issues like this it is generally a good idea to print what was read. ...and, of course, you always need to verify that the read was actually successful.

getchar() doesn't actually take input from user

I am writing a flexible command-line (but not for long!) diamond-square generator in C++. I have just finished writing the user input half. However, on the very last command, input "slips" and a newline is automatically inputted to getchar(). I have taken precautions to ensure that it's not any sort of overflow, namely, fflushing both stdin, and, for good measure, stdout. The problem persists. Here is my code:
#include <stdio.h>
#include <stdlib.h>
int main () {
unsigned long seed = 0, x = 0, y = 0, initial = 0, range = 0;
int smooth = 0, fail = 1;
char flagchar1 = 'n';
printf("Welcome to my diamond-square generator! This isn't full-feature yet, so I'm just gonna have you input the variables one by one. ");
do {
printf("Please input the seed (this is a positive integer):\n");
fail = scanf("%lu", &seed);
while (fail == 0) {
printf("Try again, smartass.\n");
fail = scanf("%lu", &seed);
}
fail = 1;
printf("Now input the x, or horizontal, size of your grid:\n");
fail = scanf("%lu", &x);
while (fail == 0) {
printf("An integer. Not a string. An integer. You can do that, can't you?\n");
fail = scanf("%lu", &x);
}
fail = 1;
printf("Now input the y, or vertical, size of your grid:\n");
fail = scanf("%lu", &y);
while (fail == 0) {
printf("What was that supposed to be? An integer, please.\n");
fail = scanf("%lu", &y);
}
fail = 1;
printf("Now input about how high you'd like the grid to be (this goes from a scale of 1 to 256):\n");
fail = scanf("%lu", &initial);
while (initial == 0 || initial > 256 || fail == 0) {
printf("ahahahahaha how HIGH do you have to be just to HAVE that hieght........\n");
fail = scanf("%lu", &initial);
}
fail = 1;
printf("Now input the range of the heights on your grid (this must be equal to or less than 256):\n");
scanf("%lu", &range);
while (range >= 256 || fail == 0) {
printf("What did I say about being equal to or less than 256? Give me something reasonable to work with here.\n");
fail = scanf("%lu", &range);
}
fail = 1;
printf("Just one more variable to go! Now, I need you to input the smoothness of your grid. Smaller numbers make spikier grids. You can make this negative, but beware!\n");
fail = scanf("%d", &smooth);
while (fail == 0) {
printf("That... was not a number.\n");
fail = scanf("%d", &smooth);
}
fail = 1;
printf("\nOkay. Are these the values you want?\n Seed: %lu\n Width: %lu\n Length: %lu\n Height: %lu\n Range: %lu\n Smoothness: %d\nDo you want to keep these? Type Y/n.\n", seed, x, y, initial, range, smooth);
fflush(stdin);
fflush(stdout);
flagchar1 = getchar();
} while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');
}
Here is my output, the program having ended (the program just repeats the entire do-while loop if I remove the && flagchar1 != '\n' from while()):
Welcome to my diamond-square generator! This isn't full-feature yet, so I'm just gonna have you input the variables one by one. Please input the seed (this is a positive integer):
12345678
Now input the x, or horizontal, size of your grid:
40
Now input the y, or vertical, size of your grid:
30
Now input about how high you'd like the grid to be (this goes from a scale of 1 to 256):
1288
ahahahahaha how HIGH do you have to be just to HAVE that hieght........
128
Now input the range of the heights on your grid (this must be equal to or less than 256):
30
Just one more variable to go! Now, I need you to input the smoothness of your grid. Smaller numbers make spikier grids. You can make this negative, but beware!
10
Okay. Are these the values you want?
Seed: 12345678
Width: 40
Length: 30
Height: 128
Range: 30
Smoothness: 10
Do you want to keep these? Type Y/n.
What's happening, and how do I fix it?
P.S. I know my input validation is essentially useless. Help with this is also greatly appreciated.
Make the end of your loop look like this:
// Ignore remaining characters on current line.
int ch;
while( (ch = getchar()) != EOF && ch != '\n')
;
// fetch first character on next line
flagchar1 = getchar();
} while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');
You are leaving the '\n' in stdin after your last call to scanf.
You must not rely upon fflush(stdin) having any specific behavior. The result of invoking fflush on a input stream is undefined. See Using fflush(stdin)
The code is behaving exactly as you tell it to. If the user enters 'y', 'Y' or enter, one of those conditions in the while loop will be false, which causes it to exit.
What you want is:
while (flagchar1 == 'y' || flagchar1 == 'Y' || flagchar1 == '\n');
Edit: I would also delete the fflush(stdin) and replace getchar() with fgets(). That will guarantee the entire line is read without having to use fflush, which may be the issue.
I'm guessing you are on Linux? This works fine on VS in Windows. It prompts, reads from keyboard, and if examined contains the correct 'y' or 'Y' in question.
I might suggest you try changing the last scanf to:
fail = scanf("%d ", &smooth);
You could also try calling fpurge() instead of fflush(), but that's non standard, and I think the space at the end of the format string will get you what you want.
The trailing space will ask scanf to consume any extra whitespace (including newlines) in the input data. fflush() probably won't do what you want for input.
I suspect whatever system you are on is indeed leaving the carriage return in the stream and if you print flagchar1 as an int you'll get 10?
Suggestions:
Use C++ streams.
Use tolower or toupper before comparing characters.
Use std::string.
The C language, which uses fgets, gets, fflush, strcmp, has many issues in this area. The C++ language has resolved many of these issues in the std::stream classes.
Since you are not using C++ features, you should change the C++ tag to C.
Try
} while (flagchar1 != 'y' || flagchar1 != 'Y' || flagchar1 != '\n');
instead of
} while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');