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.
Related
I'm trying to read a text file consisting of numerous strings which either represent a key/value (the key is a car number in a format of a letter/' '/3digits/' '/2letters; the value is unsigned long long; \t or ' ' between them) or an empty line, e.g.:
empty line
empty line
Z 999 ZZ 80
A 000 AA 124
Z 666 ZZ 42
I am using a cin.getline() function for that, reading a whole line and going through every character, saving a key and a value into an 'element' variable and pushing it into a vector afterwards. But for some reason the program seems to work unexpectedly, giving a weird output:
0
0
Z 999 ZZP 80
A 000 AA| 124
Z 666 ZZ* 42
So far I have been trying to analyse what could go wrong but I just can't see it. I've also tried using other tools like scanf() or cin.get() but failed miserably. Can someone please explain to me why this is happening and maybe show a more correct way of solving this task? Here is the code:
struct kv {
char key[8];
unsigned long long val;
};
int main()
{
std::vector<kv> data_vector;
kv element;
char str[64] = {};
char num[32] = {};
while (std::cin.getline(str, 64)) {
if (str[0] == ' ' || str[0] == '\n' || str[0] == '\t' || str[0] == EOF) {
continue;
}
size_t i = 0, n = 0;
for (i = 0; i < 8; i++)
element.key[i] = str[i];
while (!(str[i] >= '0' && str[i] <= '9'))
i++;
while (str[i] >= '0' && str[i] <= '9')
num[n++] = str[i++];
element.val = atoi(num);
data_vector.push_back(element);
for (n = 0; n < 32; n++)
num[n] = 0;
for (i = 0; i < 64; i++)
str[i] = 0;
}
for (size_t i = 0; i < data_vector.size(); i++) {
std::cout << data_vector[i].key << "\t" << data_vector[i].val << std::endl;
}
return 0;
}
EDIT: as #JimRhodes pointed out, changing char key[8] to char key[9] and adding element.key[8] = '\0' helped, but empty lines are still being processed the wrong way (as they should be ignored), giving an output of 0.
I think you may not be understanding how std::cin.getline() works. First of all, you do not want to test the return value of std::cin.getline() for true or false. You need to check for eof or fail. Secondly, std::cin.getline() discards the newline character so there is no need to check for '\n'. Your loop could start like this:
for ( ; ; )
{
str[0] = '\0'; // Clear any previous data
std::cin.getline(str, 64);
if ( std::cin.eof() )
{
break; // No more data, exit loop
}
if ( std::cin.fail() || (str[0] < 'A') )
{
continue; // Empty line or line does not start with a letter
}
. . .
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
}
My target is to validate c++ input that it will hold only small and capital letters and empty space. Can I do that without for loop? My current code is:
bool validateInput()
char c;
string result;
cin >> result;
for (int i = 0; i < result.length(); i++) {
c = result.at(i);
if ( !( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == ' ' ) )
{
return false;
}
}
}
You can do it without a for loop, although you'll obviously still need to use a loop, I guess the modern C++ way would be to use std::find_if , ( you can also use std::none_of as pointed out by #NathanOliver which wraps std::find_if and returns a boolean instead of an iterator ). It's also probably a good idea to use std::isalpha, partly because a character set might not have alphabetical characters mapped to decimal values in order, and partly because it is easier to write :-)
bool validateInput()
{
std::string result;
std::cin >> result;
return std::none_of(result.begin(), result.end(), [](const char& c)
{
return !(std::isalpha(c) || c == ' ');
});
}
string removeNonAlphas(string original)
{
for(int i = 0; i < original.size(); ++i){
if(!(original[i] > 64 && original[i] < 91) &&
!(original[i] > 96 && original[i] < 124)){
original[i] = original[i] - original[i];
}
}
return original;
}
//test1.cpp
string test = "abc abc";
cout << removeNonAlphas(test) << endl; // output = "abcabc"
assert(removeNonAlphas(test) == "abcabc"); // assertion failed
//Why does assertion fail above? removeNonAlphas result("abcabc") is same as
//rhs "abcabc"
original[i] = original[i] - original[i];
What this makes is that it repaces the character with '\0' but does not remove it. Because of that the output is not "abcabc" but "abc\0abc". '\0' is non-printable so you won't see it in the output but it is present when you compare it with ==.
Instead of replacing charactes in a string, create a new string while iterating the old one:
string removeNonAlphas(string const& original)
{
std::string result;
for(char c : original)
if((c > 64 && c < 91) ||
(c > 96 && c < 124))
result.push_back(c);
return result;
}
Note: prefer using std::isalpha instead of hard-coded values.
Both values are NOT the same, but the difference is a non-printing character, so you can't see any difference with cout and your naked eye.
Try a proper tool, like a debugger, and you will see the extra \0 character present in the function result.
You're not actually erasing any characters from your string. You're just assigning them the value 0. It just looks like it works - which is just the worst. The '\0' is just a non-printable character, which is why it looks like it prints the same. The == will actually check every character, even the non-printable ones, so it'll catch what you can't see.
Thankfully, the string class makes it easy to erase characters by providing just such a member function:
original.erase(i, 1); // erase a single character starting at i
Now that alone isn't enough. You erase a character, and now i is "pointing" to the next element - but you won't check it. If we had "abc12abc", after erasing the 1, we'd skip the 2. So we need to change how we iterate:
for (std::string::iterator it = original.begin();
it != original.end();
/* nothing */)
{
// here's a better way to do checking
if (!(*it >= 'A' && *it <= 'Z') &&
!(*it >= 'a' && *it <= 'z'))
{
// erase(iterator ) will return the next iterator
it = original.erase(it);
}
else
{
++it;
}
}
That'll work. It's also very verbose. And error-prone. Which is why we have the erase-remove idiom:
original.erase(
std::remove_if(original.begin(),
original.end(),
[](char c) { return !std::isalpha(c); }),
original.end()
);
return original;
#include <iostream>
using namespace std;
Int main() {
cout<<"Give me a letter" <<endl;
char letter;
cin>>letter;
cout<<letter;
(Int)letter;
letter+=2;
cout<<(char)letter;
(Int)letter;
letter-=25;
cout<<(char)letter;
return 0;
}
How would I manipulate the numbers in a way so that the numbers will always output a letter.
ie: if the letter z was chosen and adding 2 is a symbol how would I manipulate it in a way so that it will always stay between the numbers for capital numbers and uncapitalized numbers. Thanks. Please try to keep answers at a beginner level please I am new to this.
if(letter > 'z') {
//do stuff
}
if(letter < 'a' && letter > 'Z') {
//do stuff
}
if(letter < 'A') {
//do stuff
}
It just depends on how you want to handle the character when it goes into one of the three ranges on the ASCII chart in which the characters are not letters.
As a side note, you don't have to cast a char to an int to do math with it.
char myChar = 'a' + 2;
cout << myChar;
This will print: c
c has an ASCII value of 2 more than a.
The surest method is to use a table for each category, and do
your arithmetic on its index, modulo the size of the table.
Thus, for just lower case letters, you might do something like:
char
transcode( char original )
{
char results = original;
static std::string const lower( "abcdefghijklmnopqrstuvwxyz" );
auto pos = std::find( lower.begin(), lower.end(), results );
if ( pos != lower.end() ) {
int index = pos - lower.begin();
index = (index + 2) % lower.size();
results = lower[ index ];
}
return results;
}
This solution is general, and will work regardless of the sets
of letters you want to deal with. For digits (and for upper and
lower case, if you aren't too worried about portability), you
can take advantage of the fact that the code points are
contiguous, and do something like:
char
transcode( char original )
{
char results = original;
if ( results >= '0' && results <= '9' ) {
char tmp = results - '0'
tmp = (tmp + 2) % 10;
results = tmp + '0';
}
return results;
}
An alternative implementation would be to use something like:
results = results + 2;
if ( results > '9' ) {
results -= 10;
}
in the if above. These two solutions are mathematically
equivalent.
This is only guaranteed to work for digits, but will generally
work for upper or lower case if you limit yourself to the
original ASCII character set. (Be aware that most systems today
support extended character sets.)
You can test directly against ASCII chars by using 'x' notation. Further, you can test things together using && ("and" respectively"):
if ('a' <= letter && letter <= 'z') {
// Letter is between 'a' and 'z'
} else if ('A' <= letter && letter <= 'Z')) {
// Letter is between 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}
Or you can use the standard library function std::isalpha which handles this for you:
if (std::isalpha(letter)) {
// Letter is between 'a' and 'z' or 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}