Number of vowels including "Y"

Viewed 152

I have to write a function that prints out all vowels in a given string line including Y, unless Y is followed by another vowel.

For example:

"test phrase" returns 3
"yes no why not?" returns 4

I've tried using getline(), but I'm not sure if there's a way to use it without requiring some type of input from the user. I need it to use an already declared string.

Here's my code that somewhat works, but takes an input.

#include <iostream>
#include <string>
using namespace std;

int numVowelsIncludingY(string line){
  int v = 0;
  getline(cin, line);

  for(int i = 0; i < line.length(); ++i){
    if(line[i] == 'A' || line[i] == 'E' || line[i] == 'I' || line[i] == 'O' || line[i] == 'U' || line[i] == 'Y' ||
       line[i] == 'a' || line[i] == 'e' || line[i] == 'i' || line[i] == 'o' || line[i] == 'u' || line[i] == 'y'){
        ++v;
    }
  }
  return v;
}

UPDATE

I've removed getline and reading the string works fine, but I'm still confused on how to count Y as a vowel only if it's not followed by another vowel.

#include <iostream>
#include <string>
using namespace std;

int numVowelsIncludingY(string line){
  int v = 0;

  for(int i = 0; i < line.length(); ++i){
    if(line[i] == 'A' || line[i] == 'E' || line[i] == 'I' || line[i] == 'O' || line[i] == 'U' || line[i] == 'Y' ||
       line[i] == 'a' || line[i] == 'e' || line[i] == 'i' || line[i] == 'o' || line[i] == 'u' || line[i] == 'y'){
        ++v;
    }
  }
  return v;
}
3 Answers

You do not need to use getline inside the function when you pass the string as parameter. Though you can read the string outside of the function from some stream. For example to test with different input you could write:

void test(std::istream& input_stream) {
    std::string line;
    std::getline(input_stream,line);
    std::cout << line << ": " << numVowelsIncludingY(line) << "\n";
}

int main(){
    std::stringstream test1{"test phrase"};
    test(test1);
    std::stringstream test2{"yes no why not?"};
    test(test2);
    std::stringstream test3{"ya"};
    test(test3);
    std::stringstream test4("aa");
    test(test4);
}

And expect output:

test phrase: 3
yes no why not?: 4
ya: 1
aa: 2

test can as well be called with std::cin to read input from the user.

For your special condition of Y not followed by a vowel you need to be careful at the boundaries to avoid out-of-bounds access. I suggest to spend a line of code extra for the last character then we can assert for the main part that every character has a next character.

Because we need to check a character for being a vowel at least twice, I decided to use a lambda expression, and while I was at it, I also wrote one to check for Y or y.

There are many ways to check if a character is a vowel. I consider it simple to search for the character in the string "AEIOUaeio". std::string::find returns std::string::npos when the character cannot be found, otherwise we know its a vowel.

#include <iostream>
#include <string>
#include <sstream>

int numVowelsIncludingY(const std::string& line){
  if (line.size() == 0) return 0;
  auto is_vowel = [](char c){
    std::string vowels{"AEIOUaeiou"};
    return vowels.find(c) != std::string::npos;    
  };
  auto is_y = [](char c){ return c == 'Y' or c == 'y'; };

  size_t counter = 0;
  for (size_t i = 0; i < line.size() -1; ++i){
      auto& c = line[i];
      auto& next = line[i+1];
      if (is_vowel(c) or ( is_y(c) and !is_vowel(next) )) ++counter;
  }
  if (is_vowel(line.back()) or is_y(line.back())) ++counter;
  return counter;
}

Live Demo

^^ Try to experiment by calling test(std::cin) and type some input in godbolts stdin field.

Here's a program that satisfies your test cases, and a couple others. I have two functions to this job. The first checks for a 'traditional' vowel. It was easier to do this than to try to add the conditions for 'Y' at this point.

Then, in count_vowels(), I check if I should count a 'Y' or not. There are two cases needed because the first case does not want to go out of bounds of the std::string. It can handle 'Y' anywhere in the word except the last position. The second case checks if 'Y' is the last letter, and counts it.

#include <cctype>
#include <iostream>
#include <string>

// Simple vowel check; the condition on 'Y' comes in count_vowels()
bool is_capital_vowel(char c) {
  return c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U';
}

int count_vowels(std::string str) {
  int count = 0;

  for (auto& c : str) {
    c = std::toupper(c);
  }

  for (std::size_t i = 0; i < str.length(); ++i) {
    if (str[i] == 'Y' && (i + 1) < str.length() &&
        !is_capital_vowel(str[i + 1])) {
      ++count;
    } else if (str[i] == 'Y' && (i + 1) == str.length()) {
      // The last character being 'Y' required some special consideration
      ++count;
    } else if (is_capital_vowel(str[i])) {
      ++count;
    }
  }

  return count;
}

int main() {
  std::string wordOne = "backyard";         // Should count 2
  std::string wordTwo = "cardigan";         // Should count 3
  std::string wordThr = "telephoney";       // Should count 5
  std::string testOne = "test phrase";      // Should return 3
  std::string testTwo = "yes no why not?";  // Should return 4

  std::cout << wordOne << ": " << count_vowels(wordOne) << " vowels.\n";
  std::cout << wordTwo << ": " << count_vowels(wordTwo) << " vowels.\n";
  std::cout << wordThr << ": " << count_vowels(wordThr) << " vowels.\n";
  std::cout << testOne << ": " << count_vowels(testOne) << " vowels.\n";
  std::cout << testTwo << ": " << count_vowels(testTwo) << " vowels.\n";
}

I deleted my last answer as I didn't understand your question correctly. But now here's the code that should work as intended. And yeah you should not use using namespace std, it is considered a bad practice. Look here: Why is "using namespace std;" considered bad practice?

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

int numVowelsIncludingY(std::string line) {
  int v = 0;

  std::vector<char> vovels{'a', 'e', 'i', 'o', 'u', 'y'};
  for (size_t i = 0; i < line.length(); ++i) {
    char ch = tolower(line[i]);
    if (ch == 'y' && find(vovels.begin(), vovels.end(), tolower(line[i + 1])) !=
                         vovels.end()) {
    } else if (find(vovels.begin(), vovels.end(), ch) != vovels.end()) {
      ++v;
    }
  }
  return v;
}
int main(void) {

  std::cout << numVowelsIncludingY("yy");

  return 0;
}
Related