The "disemvowels" exercise. Here are the specifications:
Write a program that removes all vowels from a file (“disemvowels”). For
example, Once upon a time! becomes nc pn tm! . Surprisingly often, the
result is still readable; try it on your friends.
The problem I'm having is with printing out a string at all (nothing gets printed). Here's the code:
void print_word(std::istream &is, std::string &word)
{
usingnamespace std;
while (getline(is, word))
{
for ( size_t position = 0; position < word.size(); position++ ) //<==== need full loop on position
{
if (!is_vowel(word[position]))
{
cout << word[position];
}
}
cout << '\n'; //<==== line break inside the while
}
}
// chapter11ex3.cpp : Defines the entry point for the console application.
// Osman Zakir
// 3 / 2 / 2017
// Bjarne Stourstrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 11 Exercise 3
// Exercise Specifications:
/**
* Write a program that removes all vowels from a file (“disemvowels”). For
* example, Once upon a time! becomes nc pn tm!. Surprisingly often, the
* result is still readable; try it on your friends.
*/
#include "../../cust_std_lib_facilities.h"
#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>
#include <sstream>
#include <cctype>
bool is_vowel(constchar ch);
void print_word(std::istream &is, std::string &word);
int main()
{
usingnamespace std;
cout << "Please enter input file name\n";
string iname;
cin >> iname;
ifstream ifs{ iname };
try
{
if (!ifs)
{
error("can't open input file", iname);
}
}
catch (const runtime_error &e)
{
cerr << "runtime error: " << e.what() << '\n';
keep_window_open();
return 1;
}
string word;
print_word(ifs, word);
keep_window_open();
}
bool is_vowel(constchar ch)
{
bool is_vowel = true;
char new_ch = ch;
new_ch = tolower(ch);
switch (new_ch)
{
case'a':
case'e':
case'i':
case'o':
case'u':
break;
default:
is_vowel = false;
break;
}
return is_vowel;
}
void print_word(std::istream &is, std::string &word)
{
usingnamespace std;
size_t position = 0;
while (getline(is, word))
{
for (size_t i = 0; i < word.size(); ++i)
{
if (!is_vowel(word[i]))
{
cout << word[i];
}
}
cout << '\n';
}
}
One thing I don't like here is that I can't make the string passed to my print_word() function const with the way I wrote the code. Everything else is fine.
One thing I don't like here is that I can't make the string passed to my print_word() function const with the way I wrote the code.
You are reading lines into word within print_word(). However, you could (probably more naturally) read each line in main() and send the line to print_word(). You have no further need to change it, so you can make it const std::string &word.
Thomas - so some way to go then, good luck Dragon. Many might raise an eyebrow but I find Stourstrup very difficult to follow and sometimes unnecessarily compicated so I stay well clear of his literary works so to speak. But then others might point out it explains a lot about my C++ :))
Desirable to whom? In your is_vowel() function why did you use that switch case statement instead of a simple if statement. All of your case statements are empty so why even have them?
#include <iostream>
#include <fstream>
#include <string>
bool is_vowel(char ch); // Sending a copy so no need for the const qualifier.
void print_word(const std::string& word);
/* No sense to pass the string, you're resetting it several
times in the function and you never actually use the "returned" string anyway so make the
"string" local to this function instead. Pass an istream so you can print somewhere other than
cout if you so desire. */
void read_words(std::istream& is);
void keep_window_open() {}
int main()
{
std::cout << "Please enter input file name\n";
std::string iname;
std::cin >> iname;
std::ifstream ifs{ iname };
// No neead to complicate things with the exceptions. Just print the message and return to the operating system.
if(!ifs)
{
std::cerr << "Runtime Error: Can't open input file!\n";
keep_window_open();
return 1;
}
read_words(ifs);
keep_window_open();
return 0;
}
bool is_vowel(char ch)
{
const std::string vowels{"aeiouAEIOU"};
return(vowels.find_first_of(ch) != std::string::npos);
}
void print_word(std::ostream& fout, const std::string &word)
{
for(auto& itr : word)
if(!is_vowel(itr))
fout << itr;
fout << '\n';
}
void read_words(std::istream &is)
{
std::string line;
while(getline(is, line))
print_word(std::cout, line);
}
// chapter11ex3.cpp : Defines the entry point for the console application.
// Osman Zakir
// 3 / 2 / 2017
// Bjarne Stourstrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 11 Exercise 3
// Exercise Specifications:
/**
* Write a program that removes all vowels from a file (“disemvowels”). For
* example, Once upon a time! becomes nc pn tm!. Surprisingly often, the
* result is still readable; try it on your friends.
*/
#include "../../cust_std_lib_facilities.h"
#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
bool is_vowel(constchar ch);
void print_word(std::ostream &os, std::string &word);
void read_words(std::istream &is);
int main()
{
usingnamespace std;
cout << "Please enter input file name\n";
string iname;
cin >> iname;
ifstream ifs{ iname };
if (!ifs)
{
cout << "runtime error: can't open input file " << iname << '\n';
keep_window_open();
return 1;
}
read_words(ifs);
keep_window_open();
}
bool is_vowel(constchar ch)
{
usingnamespace std;
const string vowels{ "aeiouAEIOU" };
return (vowels.find_first_of(ch) != string::npos);
}
void print_word(std::ostream &os, std::string &word)
{
usingnamespace std;
for (constchar ch : word)
{
if (!is_vowel(ch))
{
os << ch;
}
}
os << '\n';
}
void read_words(std::istream &is)
{
usingnamespace std;
string word;
while (getline(is, word))
{
print_word(cout, word);
}
}
Thanks for the help, anyway.
And Thomas, yeah, I agree with you about the complexity. Stroustrup stresses simplicity of code a lot, but he still has really hard-to-understand, complicated code in the book. I understand that the concepts used are simple, but his own coding style still isn't. It can also be hard to tell sometimes what part of some given code with a loop belongs inside the loop and what part doesn't, though I think I'll be able to tell more easily now with experience.
There is really no need to pass that single char as a const, your passing by value which means that any changes made in that function will be lost when the function returns anyway.
But you really should be passing word as a const, since you're passing this by reference any changes inadvertently made in the function would be reflected in the calling function.
IMO, you're overusing the using namespace std clause. While it is usually better to keep the use of the using clause local to functions, putting the using clause in every function is no better than using a more global using statement. In most of your functions you would be better off just properly scoping the one or two terms that might require scoping instead of the using statement. About the only place in this program I might use the using statement would be possibly main().
Lastly, you probably should either be writing your error messages to std::err rather than std::cout or if you use std::cout you should either use std::flush or std::endl to insure the stream is promptly flushed to the output device.