I'm trying to solve a problem and i can't figure out how to do it.
The problem says that given an input file which has on the first line a number k and on the next lines some words, K is the minimum number of vowels that a word needs to have to be printed in the console.
Example:
Input: test.in
cars
are...great and awesome
Output:
If k is 2 the result should be:
are
great
awesome
And also it should not take into account spaces or other characters like .,!,? and so on.
What i have so far:
int main(){
ifstream fin("dataTest.in");
char s[250];
int k;
fin>>k;
int nrVowels=0;
while(fin>>s) {
int n = strlen(s);
for(int i=0; i < n; i++)
{
if (s[i] == 'a' || s[i] == 'e' || s[i] == 'o' || s[i] == 'i' || s[i] == 'u'){
nrVowels++;
if(nrVowels == k){
cout<<"Here i guess i should print the word?";
}
}
}
}
}
As you can see from the code my problem is that i'm not really sure how i should print the word and how would i know where the word is ending because i don't want to print only a part of the word.
Do you guys have any ideas on how i should do this?
std::ifstream file("Read.txt");
int number;
file>>number;
std::string str;
auto vowels = [](char c){return c == 'a' || c == 'e' || c == 'o' || c == 'i' || c == 'u';};
while (std::getline(file, str))
{
if(std::count_if(str.cbegin(), str.cend(), vowels) >= number){
std::cout<<str<<'\n';
}
}
Thanks for answering!
I've modified my code with this based on your help:
int main(){
ifstream fin("dateTest.in");
char s[250];
int k;
fin>>k;
int nrVowels=0;
while(fin>>s) {
int n = strlen(s);
nrVowels=0;
for(int i=0; i < n; i++)
{
if (s[i] == 'a' || s[i] == 'e' || s[i] == 'o' || s[i] == 'i' || s[i] == 'u'){
nrVowels++;
if(nrVowels >= k){
cout<<s<<" ";
break;
}
}
}
}
}
It kind of works now but i need also to separate words that have.,? and so on. How should that be done?
Your requirements state that "K is the minimum number of vowels that a word needs to have to be printed in the console", which would translate to the greater or equal condition
if (nrVowels >= k) { /* print word */ }
However, your code prints the word as soon as k
vowels are found, so you can keep your condition as is. But you should break the inner loop once the required count was reached.
Also, as it was commented already, you need to reset the nrVowels
counter for each word that you inspect. Better yet: make nrVowels
a local scope variable within the body of your while-loop.
Some hints regarding your code that are not strictly necessary to solve the problem:
- use
std::string
instead of char arrays.
- use a single variable that contains all your vowels
- don't count vowels, just ensure there are at least two in the word
code:
ifstream fin("dataTest.in");
std::string s;
const char* vowels = "aeiou";
int k;
fin>>k;
while(fin>>s)
{
// If the string contains at least two vowels, the find results will differ
if (s.find_first_of(vowels) != s.find_last_of(vowels))
{
std::cout << s << std::endl;
}
}
First fix obvious problems
int main(){
ifstream fin("dataTest.in");
char s[250];
int k;
fin>>k;
while(fin>>s) {
int nrVowels=0; // moved
int n = strlen(s);
for(int i=0; i < n; i++) {
if (s[i] == 'a' || s[i] == 'e' || s[i] == 'o' || s[i] == 'i' || s[i] == 'u') {
nrVowels++;
if(nrVowels == k) {
cout<< s;;
break; // inner for
}
}
}
}
}
You have
char s[250];
in combination with
fin>>s
is a potential buffer overrun. changing s to
std::string s;
now you get
int n = strlen(s);
for free.
if (s[i] == 'a' || s[i] == 'e' || s[i] == 'o' || s[i] == 'i' || s[i] == 'u')
is rather long it would be better to say
if (IsVowel(s[i]) {
by making (as Kaldrr proposed)
auto IsVowel = [](const char c){return c == 'a' || c == 'e' || c == 'o' || c == 'i' || c == 'u';};
This gives
int main(){
ifstream fin("dataTest.in");
std::string s;
int k;
fin>>k;
auto IsVowel = [](const char c){return c == 'a' || c == 'e' || c == 'o' || c == 'i' || c == 'u';};
while(fin>>s) {
int nrVowels=0; // moved
for(int i=0; i < n; i++) {
if (IsVowel(s[i]) {
nrVowels++;
if(nrVowels == k) {
cout<< s;;
break; // inner for
}
}
}
}
}
But there is still the problem of each word is tested instead of each string.
int main(){
ifstream fin("dataTest.in");
std::string s;
int k;
fin>>k;
auto IsVowel = [](const char c) { return c == 'a' || c == 'e' || c == 'o' || c == 'i' || c == 'u'; };
auto IsSplit = [](const char c) { return isspace(s[i]) || ispunct(s[i]); };
while(fin>>s) {
int nrVowels=0; // moved
for(int i=0; i < s.length; i++) {
if (IsVowel(s[i]) {
nrVowels++;
if(nrVowels == k) {
cout << s; // wrong writes all the string and not the word
break; // inner for
}
} else {
if (IsSplit(s[i]) {
nrVowels = 0; // restart at each word.
}
}
}
}
}
What we want is
while(fin>>s) {
auto split = Split(s);
for (const auto& str : split) {
if (HasEnougVowels(str, k)) {
cout << s;
}
}
}