Counting the Number of Palindromes in a Sentence - c++

Good day, everyone! Below is a program which asks a user for a sentence and outputs the number of palindromes in it.
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
bool isPalindrome (const std::string& s) {
for (int i = 0; i < (s.length())/2; ++i) {
if (s[i] != s[s.length()-1 - i])
return false;
else
return true;
}
}
int main() {
string sentence;
int counter=0;
cout << "Please input a sentence." << endl;
getline(cin, sentence);
stringstream processtokens(sentence);
for(string word; processtokens >> word;)
if(isPalindrome(word))
++counter;
cout << "Number of Palindromes are : " << counter << endl;
}
It works just fine. But for example, when I input "The quick brown gag has a blue eye.", the number of palindromes the program displays is just 1 but in reality, the sentence has 2 palindromes: gag and eye. The problem is that the word "eye" has a period. So how can the program ignore the period and other punctuation marks like comma when, for instance, the user entered "I love noon, evening, and midnight". Noon is a palindrome but the program doesn't recognize it because of the comma.
Another problem is the capitalization. I want this program to work (and ignore ASCII equivalents) when the user entered "Madam, my work is done." I know it has something to do with tolower.
To summarize, I want this program to have a function which a) ignores punctuations marks and b) capitalization.
And oh, what is the alternative for " stringstream processtokens(sentence);... "? Rather that, I need this program to use substring (substr) and find.
Please guide me, guys! Thank you and any kind of help is very appreciated. Thanks again and have a nice day!

You can use ispunct and ignore any characters where ispunct returns true. You should also wrap your character comparisons in calls tolower()

Maybe this little exercise can be used to introduce some nice C++ features such as iterators:
inline bool is_letter(char c)
{ return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); }
bool is_palindrome(const std::string & s)
{
std::string::const_iterator it = s.begin();
std::string::const_reverse_iterator rt = s.rbegin();
while (it != s.end() && rt != s.rend() && std::distance(it, rt.base()) > 0)
{
// Skip non-letters
while (it != s.end() && !is_letter(*it)) { ++it; }
while (rt != s.rend() && !is_letter(*rt)) { ++rt; }
if (it == s.end() || rt == s.rend()) { break; }
// Check palindromy
if (std::tolower(*it) != std::tolower(*rt)) { return false; }
// Move on
++it;
++rt;
}
return true;
}
The trick is to attack the string from both ends. For this, we have an ordinary iterator, it, coming from the beginning of the string, and a reverse iterator, rt, coming from the end of the string.
The heart of the code is the check for palindromy (case insensitively, by comparing downcased characters), and immediate return false in the even of failure; otherwise the two iterators are advanced by one.
Finally, the beginning of the loop gobbles up non-letter characters from the string, so those are flat-out ignored. We check again whether we reached the end of the string after gobbling; you must make sure that you only dereference an iterator to a valid element!
The loop stops when the forward-moving iterator has gone past the backward-moving one. This is the content of the condition distance(it, rt.base()) > 0: the "base" of the reverse iterator is actually an ordinary iterator to the element after the reverse-iterator's element. So it hasn't crossed over rt as long as the distance from it to the base of rt is strictly greater than zero. (The distance is precisely 1 when it and rt refer to the same element.)

I think there is a function to check for punctuation. You might want to try ispunct

Related

Counting words that start with Capital Letters C++ [Help]

Hey everyone I'm a newbie to C++ and could use some help.
I'm trying to code a program which counts only the words that start with Capital Letters.
int countLegalWords(char str[])
int counter = 0; // counts the legal words
for (int i = 0; i < MAXSIZE; i++)
{
if (str[i] >= 'A' && str[i] <= 'Z')
{
if (str[i + 1] >= 'a' && str[i + 1] <= 'z')
{
counter++;
}
else if (str[i] == ' ')
i++;
}
}
return counter;
Example:
Input:
I liKE Ice Cream H
Output:
4 words with capital letters at the beginning of the word.
There are several problems with your code
In C++, std::string is used for strings. Things like ´char*´ or ´char[]´ are not used in C++ They are used in C. But C and C++ are 2 different languages
You use a C-Style array (char str[]). In C++, C-Style arrays are not used
There is a magic constant MAXSIZE, which has nothing to do with the length of the string. If MAXSIZE is 100 but the your string is smaller, then you compare out of bounds values in the for loop. This is a severe bug.
You need to understand that C-style strings are 0-terminated. The last charcter is a '\0'. You must not operate past the terminating 0.
Your logic in detecting words and word begin is wrong. You check any character for uppercase and then the next for lowercase. But this can happen also within a word. See your sentence with "liKe" in it.
You do not want to switch to C++. You have written in the comment that you want to use strcmp and such, which is a C-function
If you would write comments and use meaningful variable names, then you would find all errors by yourself.
OK, that were the problems. Now a possible solution, using your programming style.
#include <iostream>
int countLegalWords(char myString[]) {
// Here we will store the number of words which start with a capital letter
int countOfLegalWords = 0;
// We will iterate over the complete string and check all characters
unsigned int indexInString = 0;
// Check all characters of the string until we hit the terminating 0
while (myString[indexInString] != '\0') {
// Search for the begin of a word. This is the first non-space character
while (myString[indexInString] == ' ')
++indexInString;
// OK, Now we found the begin of a word. Check, if the first character is upper case
if ((myString[indexInString] >= 'A') and (myString[indexInString] <= 'Z')) {
// Yes, uppercase, count up
++countOfLegalWords;
}
// Now search for the end of the word or for the end of the complete string
while ((myString[indexInString] != '\0') and (myString[indexInString] != ' '))
++indexInString;
}
// And return the count of legal words to ther calling program
return countOfLegalWords;
}
int main() {
char myString[] = "I liKE Ice Cream H";
std::cout << "\nCount of legal words: " << countLegalWords(myString) << '\n';
}
in C++ all this would be done with a one liner:
#include <iostream>
#include <string>
#include <iterator>
#include <regex>
// Regex for a word starting with a capital letter
const std::regex re{ R"(\b[A-Z]\w*)" };
// Main program
int main() {
std::string myString{ "I liKE Ice Cream H" };
std::cout << "\nCount of legal words: " << std::distance(std::sregex_token_iterator(myString.begin(), myString.end(),re), {}) << '\n';
}

How to read spaces, words, and letters line-by-line from a file in a function using Loops (C++)

so I am having a problem with getting my program to increment values properly.
My program needs to take a file in main(), and then pass that to a function-set to print that is called in main.
The key thing is that I need to use loops within the functions to get Letter Count, Space-Count, and Word Count.
I have the output configured right
cout << line_number << ": " << line << " [" << letter_count << " letters, " << space_count << " spaces, " << word_count << " words]" << endl;
Which results for example
0: Words go here. [# letters, # spaces, # words.]
But with my current functions for Letters and spaces, it doesn't work.
My non-space function for example
int count_non_space(string line) {
int non_space = 0;
for (int i = 0; i < line.length(); i++) {
if (line.c_str() != " ") {
non_space++;
}
}
return non_space;
It counts all of the characters in the line instead and the counterpart (space_count) counts nothing.
And that's not to mention that I don't know how to count the words in the line.
Any advice as to what is going on? as I am certain that count_space and count_non_space should be inverses of each other (count_space being the same function but with == instead of !=)
EDIT: Got the Letter and Space count correct.
Now, how would I get the word count from that sort of method?
EDIT 2: Okay so letter count is off.
It is counting puncutation-characters (commas, periods, dashes, hiphons.etc) as leters.
I have managed to redact periods, dashes.etc from the code manually with a reduction if statement in the count_non_characters function.
But I can't add ' to it as it already uses '' to catch the char comparison
Is there catch-all term for punctuation characters in C++ that I can use for
if (line[i] == "Puncutation") {
non_space--;
}
?
As UnholySheep said, when you compare a c string (char *) you can't use standard logical operators. You will need to use strcmp(). However, if you use a c++ std::string then you can use compare() or logical operators.
As for finding words in a string. Here are a few resources.
c++ counting how many words in line
C++ function to count all the words in a string
C++ Program to find number of Digits and White Spaces in a String
Count words in a given string
For further help. Google: "Get word count per line c++"
Reminder, these two are different data types and have different library support:
std::string myStr
myStr.c_str()
If the goal is to count characters in a string that are not spaces, then there is a way to do this using the STL and lambdas that is much cleaner than writing a bunch of loops and worrying about updating variables.
int count_non_space(std::string line) {
return std::count_if(line.begin(), line.end(),
[](auto ch) {
return ch != ' ';
});
}
This also makes is very straightforward to accommodate for things like spaces and tabs.
int count_non_space(std::string line) {
return std::count_if(line.begin(), line.end(),
[](auto ch) {
return ch != ' ' && ch != '\t';
});
}
To count the opposite (just the spaces) we simply need to change the condition in the lambda.
int space_count(std::string line) {
return std::count_if(line.begin(), line.end(),
[](auto ch) {
return ch == ' ' || ch == '\t';
});
}
As Remy Lebeau helpfully points out, we don't even have to write the lambda. We can simply use the std::isspace function directly instead of the lambda.
int space_count(std::string line) {
return std::count_if(line.begin(), line.end(), std::isspace);
}
Documentation on std::count_if.
Here's how I would revise the function you gave:
int count_non_space(string line) {
int non_space = 0;
for (int i = 0; i < line.length(); i++) {
if (line[i] != ' ') {
non_space++;
}
}
return non_space;
}
Notes:
I changed line.c_str() to line[i] in order to access the ith character of line
I changed " " to ' ' so that it's comparing against the space char, not a string which only contains the space. The comparison would fail if we were comparing the ith char to a string
As for this:
And that's not to mention that I don't know how to count the words in the line.
I don't know how your requirements define a word, but if we assume a word is any contiguous clump of non-space characters, you could use this logic:
initialize bool in_word to false
initialize int word_count to 0
for each char in the string:
if in_word is false and the current char is not a space, then set in_word to be true and increase word_count by 1
if in_word is true and the current char is a space, then set in_word to be false
return word_count

How to fix iteration without a cause (with an input); in c++?

Just on a starting note, Please excuse the lack of c++ conventions and logic shown in this code. I'm still trying to get around formatting syntax for c++..
With this small part of a larger application building project, I am trying to create a 'data validation' type subroutine with integers and strings being the main test cases, the input coming from the intended user.
The problem is that each character of the variable input is being iterated over, even if the 'if statements' are outside of the 'for loop' (or in some other cases while loops).
An example of the error being:
Enter a value:f1o2o3
Your value is a string
Your value is a integer
Your value is a string
Your value is a integer
Your value is a string
Your value is a integer
The extra lines after the first Your value is a string and
Your value is a integer are unwanted.
I know that I could just instead return the boolean variable letexists or intexsits, with them both being iterated without a problem.
However this 'character iterating' problem has been a nuisance in other parts too and I cannot seem to find a definite, understandable fix anywhere.
I am used to using python so this 'iterating over every character while passing parameters' is quite new to me.
I have tried looking into what it could be for multiple days now. Both: searching online and asking others (in person showing them code that has problems) about the 'iteration over each character' problem, however, none seem to know why this happens.
I have solved this problem in the past by breaking a while(true) loop after the intended data value has been received, however I understand this is really bad practice and therefore want to figure out how I can improve data validation.
#include <iostream> // for std::cin, std::cout
#include <string> // for string datatype
#include <algorithm> // for std::find
#include <iterator> // for std::begin, std::end
using namespace std;
// If the 'cout's are changed to returning functions I will change this to a function itself (using int datacheck(...){...})
void datacheck(string &i) {
const char nums[] = { '0','1','2','3','4','5','6','7','8','9','\0' };
const char alph[] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\0' };
for (char& c : i) {
bool intexists = find(begin(nums), end(nums), c) != end(nums);
bool letexists = find(begin(alph), end(alph), c) != end(alph);
if (letexists || (letexists && intexists))
cout << "Your value is a string" << endl;
// This will be changed for a return value
else if (!letexists && intexists)
cout << "Your value is a integer" << endl;
// This will be changed for a return value
else
cout << "Your value has an erogenous input (Special characters or non-letter/ number related stuff.";
}
}
int main(void) {
string checkedvalue;
cout << "Enter a value: ";
cin >> checkedvalue;
cin.clear();
cin.ignore(512, '\n');
datacheck(checkedvalue);
return 0;
}
I have realised that it may be because each character is being sent through individually into the subroutine, however, if this is the case I am still unsure how to fix this.
Just to end off...
Overall, an explained solution for why the iterating happens and how it can be fixed will be greatly appreciated. If possible for general cases, however, just this case will be extremely helpful nonetheless.
Thank you.
I have to admit, i dont understand all of what you write. What I did understnad is
The problem is that each character of the variable input is being
iterated over, even if the 'if statements' are outside of the 'for
loop'
And that is wrong!
for (char& c : i) {
bool intexists = find(begin(nums), end(nums), c) != end(nums);
bool letexists = find(begin(alph), end(alph), c) != end(alph);
if (letexists || (letexists && intexists))
cout << "Your value is a string" << endl;
// This will be changed for a return value
else if (!letexists && intexists)
cout << "Your value is a integer" << endl;
// This will be changed for a return value
else
cout << "Your value has an erogenous input (Special characters or non-letter/ number related stuff.";
}
All this above is "the for loop". In simple terms the syntax for a (ranged based) for loop is
for (char& c : i) {
// body of the loop
}
Your code will be more clear and readable if you use {} also for the if, even if not needed and proper intendation:
for (char& c : i) {
bool intexists = find(begin(nums), end(nums), c) != end(nums);
bool letexists = find(begin(alph), end(alph), c) != end(alph);
if (letexists || (letexists && intexists)) {
cout << "Your value is a string" << endl;
} else if (!letexists && intexists) {
cout << "Your value is a integer" << endl;
} else {
cout << "Your value has an erogenous input (Special characters or non-letter/ number related stuff.";
}
}
In C++, the standard provides different ways to checks if an string contains alpha/numeric values:
Check if all characters are numeric: std::isalnum
Check if all characters are alpha: std::isalpha
So you can replace part of your code with:
const all_numeric = std::all_of(std::begin(str), std::end(str), [](const auto c) {
return std::isalnum(c);
})
const all_alpha = std::all_of(std::begin(str), std::end(str), [](const auto c) {
return std::isalpha(c);
})
So to solve your problem, you can start by creating a helper function that checks if a string is a number by using standard functions like strtool or recycle what we did later:
bool is_number(const std::string& s) {
return !s.empty() && std::find_if(s.begin(),
s.end(), [](char c) { return !std::isdigit(c); }) == s.end();
}
Now that you know if the string is a number or not, you can check if your string contains any weird character, and discard it.
Updates:
void datacheck(string &i) {
const auto intexists = is_number(i);
if (intexists) {
// do whatever
return;
}
const all_alpha = std::all_of(std::begin(str), std::end(str), [](const auto c) {
return std::isalpha(c);
});
if (all_alpha) {
// do whatever
return;
}
}

Using find_first_of with a string instead of a set of predefined characters in c++

I want to take in a code, for example ABC and check whether the characters in the code appear in that exact order in a string, for example with the code ABC, and the string HAPPYBIRTHDAYCACEY, which meets the criteria. The string TRAGICBIRTHDAYCACEY with the code ABC however does not pass, because there's a "c" before the "b" after the "a". I want to use the find_first_of function to search through my string, but i want to check for any of the characters in "code", without knowing what characters are in "code" beforehand. Here is my program so far:
#include <iostream>
#include <string>
using namespace std;
int main() {
string code, str, temp;
int k = 0;
int pos = 0;
cin >> code >> str;
while (k < code.size()) {
pos = str.find_first_of(code,pos);
temp[k] = str[pos];
++k;
++pos;
}
cout << temp << endl; // debug. This is just outputs a newline when i
//run the program
if (temp == code) {
cout << "PASS" << endl;
}
else {
cout << "FAIL" << endl;
}
return 0;
}
I think your best bet is to find just the first character, once found, find the next in the remainder of the string, repeat until end of string or all characters found (and return false or true, respectively).
I don't think there's anything builtin for this. If the characters would need to appear directly after each other, you could use std::string::find() which searches for a substring, but that is not what you want.

c++ programming iteration and recursion

I am looking for some quick tips on a homework assignment. We are given a few problems and have to write two quick programs on how to solve the problems with one each of iteration and recursion. I'm sure this is easier than I think, but I am getting easily confused over the two. By no means do I want anyone to fully solve the problems for me, I won't learn anything! But if you could look at what I have so far and let me know if I am heading in the right direction. Also, the code does not need to compile, our professor wants us to have a general idea of the differences of iteration vs. recursion.
Problem: check a string to see if it is a palindrome.
My solution- I think it is the iterative solution:
bool iterative_palindrome (const string& str) {
string line, result;
stack <char> stack_input;
//user enters string, program takes it
cout << "Enter string: " << endl;
while (getline (cin, line) && (line != "")) {
//push string into stack
for (size_t i = 0; i < line.size(); i++) {
stack_input.push(line[i]);
//create reverse of original string
while (!stack_input.empty()) {
result += stack_input.top();
stack_input.pop();
return result;
}
//check for palindrome, empty string
if (line == result || line = "0" || line.empty()) {
return true;
cout << line << " is a palindrome!" << endl;
} else {
return false;
cout << line << " is NOT a palindrome." << endl;
cout << "Enter new string: " << endl;
}
}
}
}
I remind everyone, I am pretty new to this stuff. I've read a few things already, but am still having a hard time wrapping my head around this.
Here's the general idea:
Iterative:
Initialize two pointers one pointer to the start and end of the string.
Compare the characters pointed, if different -> not palindrome.
Increase the start pointer and decrease the end pointer.
Repeat until start pointer >= end pointer.
Recursive (more difficult than iterative in this case):
End condition: A string of length zero or one is a palindrome.
A string is a palindrome if the first and last characters are the same and if the string without the first and last characters is a palindrome.
You can implement this recursive algorithm more efficiently by passing pointers to the first and last character in the string instead of copying the string between recursions.
Hope this helps :-)
I figure writing code is the best way to explain the two approaches. Is this code understandable?
bool iterative_palindrome(const string& str) {
int size = str.size();
for (int i=0; i<str.size()/2; i++) {
if (str[i] != str[size-i-1])
return false;
}
return true;
}
You call this like recursive_palindrome(str, 0).
bool recursive_palindrome(const string& str, int index) {
int size = str.size();
if (index >= size/2)
return true;
if (str[index] == str[size-index-1])
recursive_palindrome(str, index+1);
else
return false;
}