Having issues comparing two characters - c++

I am currently making an integer parser using C++, and am having issues comparing two characters. I noticed that the atoi() function will allow for a string that has a '+' or '-' character, and will sign the int accordingly based on the first character of the string being either '+' or '-'. I am having an issue however with comparing. The for loop will just check the first element if it is not a digit, and if it is not a digit, it checks if it is a negative or a positive character.
Here is my code:
for (i; i < 20 && usrIpt[i] != '\0'; ++i) {
if (i == 0 && isdigit((unsigned char)usrIpt[0]) == 0) {
if (usrIpt[0] != '+' || usrIpt[0] != '-') {
isNumber = false;
break;
}
}
else {
if (isdigit((unsigned char)usrIpt[i]) == 0) {
isNumber = false;
break;
}
}
}
The issue I am having, is when usrIpt[0] is either '+' or '-', the program is not breaking from the if conditional usrIpt[0] != '+' || usrIpt[0] != '-'.

The for loop will just check the first element if it is not a digit,
First, there is no need to put this check within the for loop. Since it is always the first character to test, this test can be done independent of any loop. If the test passes, then you start the digit checking loop at either index 1 or index 0 of the string, depending on whether there is or is no sign character.
Second, your test for + and - is wrong. It will always evaluate to true.
Given all this, here is a rewrite of your code:
int loopstart = 0;
if ( !isdigit(usrIpt[0]) ) // not a digit, so see if it is + or -
{
loopstart = 1;
if (usrIpt[0] != '-' && usrIpt[0] != '+')
{
// this is not a number, so exit
}
}
Once the test is done, you will either start the loop at the first character or second character:
int len = strlen(usrIpt);
for (int i = loopstart; i < len; ++i ) // loopstart is either 0 or 1
{
// now check if all digits
}

Related

Remove extra whitespace from c++ issue

I have this code snippet from online.
void ShortenSpace(string &s)
{
// n is length of the original string
int n = s.length();
//pointer i to keep trackof next position and j to traverse
int i = 0, j = -1;
// flag that sets to true is space is found
bool spaceFound = false;
// Handles leading spaces
while (++j < n && s[j] == ' ');
// read all characters of original string
while (j < n)
{
// if current characters is non-space
if (s[j] != ' ')
{
//if any preceeding space before ,.and ?
if ((s[j] == '.' || s[j] == ',' ||
s[j] == '?') && i - 1 >= 0 &&
s[i - 1] == ' ')
s[i - 1] = s[j++];
else
// copy current character to index i
// and increment both i and j
s[i++] = s[j++];
// set space flag to false when any
// non-space character is found
spaceFound = false;
}
// if current character is a space
else if (s[j++] == ' ')
{
// If space is seen first time after a word
if (!spaceFound)
{
s[i++] = ' ';
spaceFound = true;
}
}
}
// Remove trailing spaces
if (i <= 1)
s.erase(s.begin() + i, s.end());
else
s.erase(s.begin() + i - 1, s.end());
}
The problem is if the input is: "test (multiple spaces) test (multiple spaces) test."
It will remove the last period and put output like "test test test"
It removes the whitespace correctly but somehow it is mishandling/removing the punctuation. I do not want it to remove the punctuation. I'm still beginner in C++ so I am having a hard time figuring out why.
Because it indiscriminately deletes the last character.
The last conditional should check if the last character is a white space as well:
// Trim string to result
if (i <= 1 || s[i-1] != ' ')
s.erase(s.begin() + i, s.end());
else
s.erase(s.begin() + i - 1, s.end());
I corrected the comment as well, as it does not trim the trailing white spaces, but the trailing characters that are left over after the manipulation. This algorithm clears characters it shifts ahead. If you were to leave out this last conditional, the output would be:
test test test. test. for input test test test.

C++ Validating Comma Placement in Numerical Input

I'm taking my first cs course and I'm currently learning the different ways to validate numerical inputs. Below is a bool function I wrote to check comma positions, but when I enter 65,000 it thinks the comma is in the wrong place.
bool commas(string input) {
bool commas = true;
long len = input.length();
int counter = 0;
for(int z = len-1; z >= 0; --z) {
if(counter == 3) {
if(input[z] != ',') {
commas = false;
counter = 0;
}
}
else {
if(input[z] == ',') {
commas = false;
}
else {
++counter;
}
}
}
return commas;
}
The easiest way to figure out if the comma is in the correction position is to go backwards (starting from the rightmost character) within the string.
The reason why this is easier is that if you were to start from the leftmost character and go forward, when you encounter a ,, you don't really know at that point whether that comma is in a valid position. You will only know until later on within the iteration process.
On the other hand, when you go from right-to-left, you know that if you encounter a comma, that comma is in a valid position -- there is no need to wait until you've gone further in the string to determine if the comma is valid.
To do this, it takes an adjustment in the loop to go backwards, and an additional counter to track the current group of 3 digits, since a comma can only occur after a group of 3 digits has been processed.
This is an untested example (except for the simple tests in main):
#include <string>
#include <cctype>
#include <iostream>
bool commas(std::string input)
{
// if the string is empty, return false
if (input.empty())
return false;
// this keeps count of the digit grouping
int counter = 0;
// loop backwards
for (int z = static_cast<int>(input.size()) - 1; z >= 0; --z)
{
// check if the current character is a comma, and if it is in
// position where commas are supposed to be
if (counter == 3)
{
if (input[z] != ',')
return false;
// reset counter to 0 and process next three digits
counter = 0;
}
else
// this must be a digit, else error
if (input[z] == ',')
return false;
else
// go to next digit in group of 3
++counter;
}
// the first character must be a digit.
return isdigit(static_cast<unsigned char>(input[0]));
}
int main()
{
std::string tests[] = { "123,,345",
"123,345",
"123,345,678",
"12,345",
"1223,345",
",123,345",
"1",
"",
"65,00",
"123"};
const int nTests = sizeof(tests) / sizeof(tests[0]);
for (int i = 0; i < nTests; ++i)
std::cout << tests[i] << ": " << (commas(tests[i]) ? "good" : "no good") << "\n";
}
Output:
123,,345: no good
123,345: good
123,345,678: good
12,345: good
1223,345: no good
,123,345: no good
1: good
: no good
65,00: no good
123: good
The way this works is simple -- we just increment a counter and see if the current position we're looking at (position z) in the string is a position where a comma must exist.
The count simply counts each group of 3 digits -- when that group of 3 digits has been processed, then the next character (when going backwards) must be a comma, otherwise the string is invalid. We also check if the current position is where a comma cannot be placed.
Note that at the end, we need to check for invalid input like this:
,123
This is simply done by inspecting the first character in the string, and ensuring it is a digit.

Replacing a substring with a space character

I am given a string and I have to remove a substring from it. Namely WUB, and replace it with a space character.
There are 2 WUB's between ÁRE' and 'THE'. SO the first condition in if statement is for not printing two blank spaces but on executing the code two blank spaces are being printed.
Input: WUBWEWUBAREWUBWUBTHEWUBCHAMPIONSWUBMYWUBFRIENDWUB
Output: WE ARE THE CHAMPIONS MY FRIEND
Here is my code so far:
#include <iostream>
using namespace std;
int main()
{
const string check = "WUB";
string s, p;
int ct = 0;
cin >> s;
for (int i = 0; i < s.size(); i++)
{
if (s[i] == 'W' && s[i+1] == 'U' && s[i+2] == 'B')
{
i += 2;
if (p[ct] == '32' || p.empty())
{
continue;
}
else
{
p += ' ';
ct++;
}
}
else
{
p += s[i];
ct++;
}
}
cout << p;
return 0;
}
Why is the first if statement never executed?
2 things are going to break your code:
you are doing a for loop like this int i=0;i<s.size() but reading (s[i]=='W' && s[i+1]=='U' && s[i+2]=='B')
and here: if(p[ct]=='32') you mean for sure if(p[ct]==32) or if(p[ct]==' ')
This condition
if(p[ct]=='32')
should read either
if(p[ct]==32)
or
if(p[ct]==' ')
that is, compare to the numeric value of the space character or to the space character itself.
Additionally, when your i grows close to the string's length, the subexpressions s[i+1] and s[i+2] may reach non-exiting characters of the string. You should continue looping with a i<s.length()-2 condition.
EDIT
For a full solution you need to fully understand the problem you want to solve. The problem statement is a bit vague:
remove a substring ("WUB") from (a given string). And put a space inplace of it if required.
You considered the last condition, but not deeply enough. What does it mean, 'if required'? Replacement is not required if the resulting string is empty or you appended a space to it already (when you encounter a second of further consecutive WUB). It is also not necessary if you are at WUB, but there is nothing more following it - except possibly another WUBs...
So, when you find a "WUB" substring it is too early to decide if a space is needed. You know you need a space when you find a non-WUB text following some WUB (or WUBs) and there was some text before those WUB(s).
There are actually three bugs here, so it's probably worth to conclude them in one answer:
The first condition:
if (s[i] == 'W' && s[i+1] == 'U' && s[i+2] == 'B')
is out of bounds for the last two characters. One fix would be to check the length first:
if(i < s.length() - 2 && s[i] == 'W' && s[i+1] == 'U' && s[i+2] == 'B')
There's a multicharacter-literal in
if (p[ct] == '32' || p.empty())
Use ' ' or 32 or std::isspace instead. IMO the last one is the best.
In the same condition
p[ct] == '32'
is always out of bounds: ct is equal to p.length(). (Credits to Some programmer dude, who mentioned this in the comments!) The variable ct is also redundant, since std::string knows it's length. I suggest to use std::string::back() to access the last character and reorder the condition as so:
if (p.empty() || std::isspace(p.back()))
The algorithm to this program is on the right track.
However, there is a few issues..
The for loop goes out of index. A way to solve this issue is substracting the size -3. Something like this.
for (int i=0; i<s.size()-3; i++) {
}
I do not suggest using other variables as counters like ct. In this case ct can reach an index out of bound error by using p[ct] inside the for loop.
Creating a string and using append() function will be a better solution. In this case, we iterate through each character in the string and if we find "WUB" then we append a " ". Otherwise, we append the character.
I highly recommend to write the first if() statement using substring() from C++.
This makes the code easier to read.
Substring creates and returns a new string that starts from a specific position to an ending position. Here is the syntax
syntax: substr(startingIndex, endingIndex);
endingIndex is exclusive
#include <string>
#include <iostream>
int main() {
string s, p;
cin >> s;
for(int i=0;i<s.size()-3;i++) {
if (s.substr(i, i+3) == "WUB") {
p.append(" ");
} else {
p.append(s.substr(i,i+1));
i++;
continue;
}
i+=3;
}
}

C++ how to determine if char is first char in a word

It seems like this should be simple but I can't seem to figure it out. I am trying to write a function that will return true if the character at position pos is the first character of a word. A word it this case is defined as any string of alphanumeric characters.
Here is my latest attempt:
bool wordBeginsAt (const std::string& message, int pos)
{
string temp;
int x;
for (x=pos;isAlphanumeric(message[x]==true);x++)
{
temp[x] = message[x];
}
if (temp[pos]!=0)
{
return false;
}
else
return true;
}
bool isAlphanumeric (char c)
{
return (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9');
}
By your definition, a character is the first character in a word if it is alphanumeric and either it's the first character in the string or the character before it is not alphanumeric.
Well, isAlphanumeric(message[x]==true) should have been isAlphanumeric(message[x])==true. But your code has other severe issues such as writing out of bounds of temp and the loop logic is all wrong, so I think it is best to start over.
What you need to do is:
Check if the character is alphanumeric
Check that either the previous character isn't, or there is no previous character
No loops or variables are required. The second condition would occur when pos == 0 ; you don't want to check the previous character if you are actually looking at the first character.

Scan for ASCII values of string characters

I want to check if a string contains any characters other than 0-9 or A-Z and if it does, stop the program. This is what I did:
string number_in;
for (int i = 0; number_in[i] == '\0'; i++)
{
if ( (number_in[i] < 48) || ( (number_in[i] > 57) && (number_in[i] < 65) ) || (number_in[i] > 90) )
{
cout << "\nInput number contains incorrect characters!\n";
getchar;
return 0;
}
}
But whichever string I would enter, it always skips the for loop. Why is that so?
number_in[i] == '\0' seems to be incorrect. It is the condition for the loop to continue to run.
However, there is an easier solution using std::isalnum and std::all_of:
bool stopProgramm = !std::all_of( std::begin(str), std::end(str),
[] (unsigned char c)
{ return std::isdigit(c) || std::isupper(c); } );
number_in[i] == '\0' should be number_in[i] != '\0'. The for loop to runs while the condition is true.
You should do:
#include <cctype>
// ...
char const c = number_in[i];
if ( !(isascii(c) && (isdigit(c) || isupper(c))) ) {
// ...
}
Strictly speaking, isascii(c) isn't needed, but, if you want to be cross-platform, the other is*() functions break on Windows if c isn't ASCII.