Counting occurrence of each character in string C++ - c++

So i wanted to count all the characters in a string and categorized them in vowels, consonants, and specials character. For example;
Enter string: sentence example ..
Vowels: e(5) a(1)
Consonants: s(1) n(1) t(1) c(1) x(1) m(1) p(1) l(1)
Specials: blank space .(2)
Here's coding:
void characterType(string input)
{
int vowel = 0;
int consonant = 0;
int special = 0;
int n = input.size();
int freq[26];
memset(freq, 0, sizeof(freq));
for (int i = 0; i < n; i++)
{
freq[input[i] - 'a']++;
}
cout<<"Vowels: ";
for (int i = 0; i < n; i++)
{
char character = input[i];
if(isalpha(character))
{
character = tolower(character);
if (character == 'a' || character == 'e' || character == 'i' || character == 'o' || character == 'u')
{
cout<<input[i]<<freq[input[i] - 'a']<<" ";
}
}
}
cout<<endl;
cout<<"Consonants: ";
for (int i = 0; i < n; i++)
{
char character = input[i];
if(isalpha(character))
{
character = tolower(character);
if (character != 'a' || character != 'e' || character != 'i' || character != 'o' || character != 'u')
{
cout<<input[i]<<freq[input[i] - 'a']<<" ";
}
}
}
cout<<endl;
cout<<"Specials: ";
for (int i = 0; i < n; i++)
{
char character = input[i];
if(!isalpha(character))
{
if(character == ' ')
{
cout<<"[black space]"<<freq[input[i] - 'a']<<" ";
}
else
cout<<input[i]<<freq[input[i] - 'a']<<" ";
}
}
}
And heres what ive got so far:
How do i make it not repeat the same character and why does special characters is not counting?

Since you want to do this and it's not some type of assignment, here's how I would approach the problem, using modern C++ features:
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
int main() {
std::map<char, std::size_t> occurrance;
std::string input{"This is A long string with lots of characters in it. AAA$#!#$!^^! "};
auto is_vowel = [] (char c) -> bool
{
auto lc = std::tolower(c);
return
c == 'a' ||
c == 'e' ||
c == 'i' ||
c == 'o' ||
c == 'u';
};
auto is_special = [] (char c) -> bool
{
// use ascii table to find only "non-special characters"
if(c < '0') return true;
if(c > '9' && c < 'A') return true;
if(c > 'Z' && c < 'a') return true;
if(c > 'z') return true;
return false;
};
auto vowels = std::count_if(
input.begin(),
input.end(),
is_vowel);
auto special = std::count_if(
input.begin(),
input.end(),
is_special);
for(auto c : input)
{
occurrance[c] += 1;
}
std::cout << "Vowels: " << vowels << '\n';
std::cout << "Special: " << special << '\n';
for(auto [c, count] : occurrance)
{
std::cout << c << " -> " << count << '\n';
}
return 0;
}
https://ideone.com/YVaDiI

This does the job, although you can make the output prettier... and take the uppercase letters into account.
void printCharWithFreq(string str)
{
int v=0, c=0, s=0;
// size of the string 'str'
int n = str.size();
// 'freq[]' implemented as hash table
int freq[SIZE];
// initialize all elements of freq[] to 0
memset(freq, 0, sizeof(freq));
// accumulate freqeuncy of each character in 'str'
for (int i = 0; i < n; i++)
freq[str[i] - 'a']++;
// traverse 'str' from left to right
for (int i = 0; i < n; i++) {
// if frequency of character str[i] is not
// equal to 0
if (freq[str[i] - 'a'] != 0) {
// print the character along with its
// frequency
if(str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o' || str[i] == 'u' ||
str[i] == 'A' || str[i] == 'E' || str[i] == 'I' || str[i] == 'O' || str[i] == 'U')
{ cout<<"Vowel: " << str[i] << freq[str[i] - 'a'] << " "<<endl; v+=freq[str[i] - 'a']; }
else if(str[i] == ' ' || str[i] == '.')
{ cout<<"Specials"<<endl; s++; }
else
{ cout<<"Consonant: " << str[i] << freq[str[i] - 'a'] << " "<<endl; c+=freq[str[i] - 'a']; }
// update frequency of str[i] to 0 so
// that the same character is not printed
// again
freq[str[i] - 'a'] = 0;
}
}
cout<<"Number of vowels: "<<v<<endl;
cout<<"Number of consonants: "<<c<<endl;
cout<<"Number of specials "<<s<<endl;
}
Then test it in the main function like
int main() {
string str = "some text . .";
printCharWithFreq(str);
return 0;
}
Basically, frequency is updated so it doesn't print the same character again, as it says in the comments. You also made a mistake in your code where you wrote:
character != 'a' || character != 'e' || character != 'i' || character != 'o' || character != 'u'
It is a consonant only if the input is different than ALL of the vowels, meaning you have to put &&, not ||.
As for the special characters, they can be counted with a simple counter.
The rest, I think, is clear from the comments in the code.
I adapted the code from the following source:
https://www.geeksforgeeks.org/print-characters-frequencies-order-occurrence/

Related

How do I modify an input through multiple functions in C++?

Basically I have to encode a name into a Soundex Code. The helper functions I implemented do the following:
Discard all non-letter characters from the surname: dashes, spaces, apostrophes, and so on.
Encode each letter as a digit
Coalesce adjacent duplicate digits from the code (e.g. 222025 becomes 2025).
Replace the first digit of the code with the first letter of the original name, converting to uppercase.
Remove all zeros from the code.
Make the code exactly length 4 by padding with zeros or truncating the excess.
Excuse the implementation of the helper functions, I know they could be implemented better. But when I manually pass the output from one function to another I see that the result is what I want. It's only when I combine them all into one function that I see that the output I pass is as if I didn't modify the input I passed at all. I believe my issue might have to do with passing by reference but doing that for all my functions made no difference or gave an incorrect output.
#include <iostream>
#include <string>
string removeNonLetters(string s) {
string result = "";
for (int i = 0; i < s.length(); i++) {
if (isalpha(s[i])) {
result += s[i];
}
}
return result;
}
string encode(string name) {
std::transform(name.begin(), name.end(), name.begin(), ::toupper);
string encoded = "";
for (int i = 0; i < name.size(); ++i) {
if (name[i] == 'A' || name[i] == 'E' || name[i] == 'I' || name[i] == 'O' || name[i] == 'U' || name[i] == 'H' || name[i] == 'W' || name[i] == 'Y')
encoded += '0';
else if (name[i] == 'B' || name[i] == 'F' || name[i] == 'P' || name[i] == 'V')
encoded += '1';
else if (name[i] == 'C' || name[i] == 'G' || name[i] == 'J' || name[i] == 'K' || name[i] == 'Q' || name[i] == 'S' || name[i] == 'X' || name[i] == 'Z')
encoded += '2';
else if (name[i] == 'D' || name[i] == 'T')
encoded += '3';
else if (name[i] == 'L')
encoded += '4';
else if (name[i] == 'M' || name[i] == 'N')
encoded += '5';
else if (name[i] == 'R')
encoded += '6';
}
return encoded;
}
string removeDuplicate(string encoded) {
for (int i = 0; i < encoded.size(); ++i) {
if (encoded[i] == encoded[i+1])
encoded[i] = '\0';
}
return encoded;
}
string removeZeros(string digits) {
for (int i = 0; i < digits.size(); ++i) {
if (digits[i] == '0')
digits[i] = '\0';
}
return digits;
}
string padding(string output) {
int size = output.size();
if (size < 4) {
for (int i = size; i < 4; ++i)
output += '0';
}
else if (size > 4) {
for (int j = size; j > 3; --j)
output[j] = '\0';
}
return output;
}
/* TODO: Replace this comment with a descriptive function
* header comment.
*/
string soundex(string s) {
/* TODO: Fill in this function. */
string copy = s;
removeNonLetters(s);
encode(s);
removeDuplicate(s);
s[0]= copy[0];
removeZeros(s);
padding(s);
return s;
}
int main() {
string s = "Curie";
cout << soundex(s) << '\n';
// Output should be C600 but I keep getting "Curie."
}
Your functions return the adjusted strings, that's good. But your calling code doesn't use the returned values!
Something like this is what you want.
string soundex(string s) {
/* TODO: Fill in this function. */
string copy = s;
s = removeNonLetters(s);
s = encode(s);
s = removeDuplicate(s);
s[0] = copy[0];
s = removeZeros(s);
s = padding(s);
return s;
}
If you want to change the value of a variable you normally use =. I'm sure you know that but for some reason you forgot because functions are involved.

Why I am not getting desired output for my c++ problem

I am solving a question which states: to change every '?' with 'a' in a string if doesn't contain if won't form consecutive 'a' else substitute with 'b', eg. a?b will be abb and not aab because here 2 a's are consecutive.
My problem is for i = 3 my string should be over- written with 'b ' according to my code it is entering into the desired block but the string does n't gets written with b, but in all the other case where it should be witten with 'a' it get's written .Help me out with these.
You can refer the problem statement from here to for better understanding my problem :https://www.hackerearth.com/practice/algorithms/greedy/basics-of-greedy-algorithms/practice-problems/algorithm/exploring-ruins/
#include <iostream>
using namespace std;
int main() {
string str;
cin >> str;
int n = str.size();
for(int i = 0; i < str.size(); i++) {
if(str[i] == '?') {
if(i == 0) {
if(str[i + 1] == 'a')
str[i] = 'b';
else
str[i] = 'a';
cout << "I am in if" << endl;
} else if(i == n - 1) {
if(str[i - 1] == 'a')
str[i] == 'b';
else
str[i] == 'a';
cout << "I am in if of else if " << endl;
} else {
if(str[i + 1] == 'a' || str[i - 1] == 'a') {
str[i] == 'b';
cout << "I am in if of else " << endl;
} else {
str[i] = 'a';
cout << "I am in else of else " << endl;
}
}
cout << str[i] << endl;
} else
continue;
}
cout << str << endl;
return 0;
}
Given string : ?ba??b
desired output : ababab
my output : aba?ab
It will be a lot easier for you if you would use functions to solve this problem.
bool check_neighbors_for_a(const string &str, size_t place) {
bool result = false;
if (place > 0) { // If there is a char before the current char
result = str[place - 1] == 'a'; // If the previous char is 'a' result become true
}
if (place < str.size() - 1) { // If there is a char after the current char
result = result || str[place + 1] == 'a'; // If the result has become true before this line, result will stay true. Else, result will be true if the next char is equal to 'a'.
// For example: b?a => result = (false || 'a' == 'a')
// For example: a?b => result = (true || 'b' == 'a')
// For example: a?a => result = (true || 'a' == 'a')
}
return result;
}
void replace_questions_by_a(string &str) {
for (size_t i = 0; i < str.size(); i++) {
if (str[i] == '?') {
if (check_neighbors_for_a(str, i)) { // If one of the neighbors is equal to 'a'
str[i] = 'b'; // Place 'b' instead of '?'
} else {
str[i] = 'a'; // Place 'a' instead of '?'
}
}
}
}

delete all consonents from the string "Hello, have a good day"

I have seen many good code to do this problem. I am new to coding. My question is where my logic went wrong. I think that problem is with second string str1. I din't initialize it. even when I am printing element by element withing if , it is working. but it is not working, when I am trying to print whole string str1.
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str = "Hello, have a good day", str1;
for (int i = 0, j =0; i < str.length(); ++i)
{
if((str[i]>='a'&& str[i]<='z') || (str[i]>='A'&& str[i]<='Z'))
if (str[i] == 'I' || str[i] == 'i' || str[i] == 'U' || str[i] == 'u' || str[i] == 'O' || str[i] == 'o' ||
str[i] == 'A' || str[i] == 'a' || str[i] == 'E' || str[i] == 'e' )
{
str1[j] = str[i];
//std::cout << str1[j] ;
j++;
}
else
{
str1[j] = str[i];
j++;
}
}
cout << str1 <<'\n';
}
output is just blank.
The first thing to do is to write a function that determines whether a character is a consonant:
bool is_not_consonant(char ch) {
static char consonants[] = "bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ";
return std::find(std::begin(consonants), std::end(consonants), ch) == std::end(consonants);
}
Then use that function as a predicate to std::copy_if:
std::string result;
std::string input = whatever;
std::copy_if(std::begin(input), std::end(input),
std::back_inserter(result),
is_not_consonant);
Explanation
The problem is that you don't need the else condition. All you need to do is check for a vowel, and print if found which is rightly covered in your if condition.
Code
Try this:
#include<string>
using namespace std;
int main()
{
string str = "Hello, have a good day", str1;
for (int i = 0; i < str.length(); ++i)
{
if((str[i]>='a'&& str[i]<='z') || (str[i]>='A'&& str[i]<='Z'))
if (str[i] == 'I' || str[i] == 'i' || str[i] == 'U' || str[i] == 'u' || str[i] == 'O' || str[i] == 'o' || str[i] == 'A' || str[i] == 'a' || str[i] == 'E' || str[i] == 'e' )
{
str1 += str[i];
}
}
cout << str1 <<'\n';
}

Strings Code not Working

Using the C++ language, the function LetterChanges(str) takes the str parameter being passed and modifies it using the following algorithm.
Replace every letter in the string with the letter following it in the
alphabet (ie. c becomes d, z becomes a). Then capitalize every vowel
in this new string (a, e, i, o, u) and finally return this modified
string.
#include <iostream>
using namespace std;
string LetterChanges(string str) {
// code goes here
string str2 = "abcdefghijklmnopqrstuvwxyz";
int j;
for (int i = 0; str[i] != '\0'; i++) {
for (j = 0; str2[j] != '\0'; j++) {
if (str[i] == str2[j]) {
str[i] = str2[j + 1];
}
}
}
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] == 'a') {
str[i] = 'A';
}
else if (str[i] == 'e') {
str[i] = 'E';
}
else if (str[i] == 'i') {
str[i] = 'I';
}
else if (str[i] == 'o') {
str[i] = 'O';
}
else if (str[i] == 'u') {
str[i] = 'U';
}
}
return str;
}
int main() {
// keep this function call here
cout << LetterChanges(gets(stdin));
return 0;
}
I am trying to run this code but it is not giving the desire output please help..
The Function
Let's start with your first loop:
for (int i = 0; str[i] != '\0'; i++) {
for (j = 0; str2[j] != '\0'; j++) {
if (str[i] == str2[j]) {
str[i] = str2[j + 1];
}
}
}
There are a couple things here. Firstly, we don't even need to deal with str2. Characters in C++ use ASCII encoding, meaning we can actually do something like str[i]++ to change an 'a' to a 'b' or an 'e' to an 'f', etc...
Also, I'd advise against using str[i] != '\0'. We're using the standard library strings instead of c-strings for a reason, so we might as well make our lives easier and use str.size(). Along these same lines, I'd suggest str.at(i) as opposed to str[i] as the former will do bounds checking for us.
Lastly, if you include cctype, then we can use the isalpha function to make sure we're only modifying alphabetic characters (no numbers or spaces, etc..).
Thus your first loop can become:
for (int i = 0; i < str.size(); i++) {
if(isalpha(str.at(i)){
if(str.at(i) == 'z') str.at(i) = 'a'; //special case
else str.at(i)++;
}
}
As far as your second loop, you don't even need it! We can actually incorporate everything straight into the first one. As long as we make sure to do the vowel modification after we've changed the individual letters.
A conversion from lowercase to uppercase can be done with some ASCII math as well. The difference between the lowercase and uppercase letters is 'A'-'a', so if we add that to any lowercase letter, it'll give us its uppercase version!
With all of this, we can modify your code to:
for (int i = 0; i < str.size(); i++) {
if(isalpha(str.at(i)){ //Make sure it's a letter!
if(str.at(i) == 'z') str.at(i) = 'a'; //special case
else str.at(i)++;
if(str.at(i) == 'a' | str.at(i) == 'e' | str.at(i) == 'i'
| str.at(i) == 'o' | str.at(i) == 'u') {
str.at(i) += 'A' - 'a';
}
}
Your Main
There's only one thing to fix here. Don't use gets for input. If you're looking for a single word, use the extraction operator, >>, or if you want a whole line, use getline.
string word, line;
getline(cin, line);
cin >> word;
cout << LetterChanges(line) << endl;
cout << LetterChanges(word) << endl;

Counting Multi-Character Characters in String

For example, how do you count the occurrence of "TJ" in OAEKOTJEOTJ?
if (s[i] == 'TJ') and (s[i] == 'T'+'J')
x += 1;
First one gives me an error, second one doesn't count. I need a beginner solution to this, I haven't learned very much about c++ commands yet. Thanks
int x = 0
string s;
cin >> s;
for (int i = 0; i < 100; i++)
if (s[i] == T || s[i] == t) && (s[i+1] == J || s[i+1] == j)
x += 1
cout << x << endl;
That's the excerpt from my code, it doesn't count any tj, tJ, Tj or TJ
Try using:
if(s[i] == 'T' && s[i+1] == 'J') // and make sure you do not run out of bounds of string with index i.
x += 1;
EDIT:
Based on your code:
int x = 0
string s;
cin >> s;
for (int i = 0; i < 100; i++)
if (s[i] == T || s[i] == t) && (s[i+1] == J || s[i+1] == j)
x += 1
cout << x << endl;
You should do it like following:
int x = 0
string s;
cin >> s;
for (int i = 0; i < s.length()-1; i++) // use size of string s.length()-1 to iterate the string instead of 100
if (s[i] == 'T' || s[i] == 't') && (s[i+1] == 'J' || s[i+1] == 'j') // compare the ascii values of characters like - 'T' 'J' etc.
x += 1
cout << x << endl;
std::string provides a function find which searches the string for substrings, including multi-character substrings (below, I am using C++11 syntax):
#include <iostream>
#include <string>
int main()
{
using namespace std;
string text { "OAEKOTJEOTJ" };
unsigned int occ { 0 };
size_t pos { 0 };
for (;;) {
pos = text.find("TJ",pos); // Search for the substring, start at pos
if (pos == string::npos) // Quit if nothing found
break;
++pos; // Continue from next position
++occ; // Count the occurrence
}
std::cout << "Found " << occ << " occurrences." << std::endl;
}
The way it's done above we advance by one character only after each match. Depending on whether/how we want to deal with overlapping matches, we might want to advance pos by the length of the search pattern. (See chris's comment as well.)
Try this:
#include <locale> // for tolower() function
string tolower(string s) {
tolower(s[0]);
tolower(s[1]);
return s;
}
...
int main() {
string s;
cin >> s;
int n = s.size(),cont = 0;
for(int i = 0; i < n ; ++i) {
if(tolower(s.substr(i,2)) == "tj") {
++cont;
}
}
cout << cont << endl;
return 0;
}