Problem:
Censor Unwanted words.
Solution:
Note: I am beginner and self learning programming by reading the book "Programming: Principles and Practises" by Bjarne Stroustrup and this a "try this" exercise from chapter 4.
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> words;
std::cout << "Enter a list of words.\n";
std::string temp;
while(std::cin>>temp){
words.push_back(temp);
}
for(auto w : words){
if(w=="idiot"||w=="nonsense"||w=="hyper"){
std::cout<<"BlEEP"<<" ";
}
else std::cout<<w<<" ";
}
}
Sample Test run.
-
8\$\begingroup\$ Just try not to make any clbuttic mistakes. \$\endgroup\$Fred Larson– Fred Larson2017年11月21日 19:10:17 +00:00Commented Nov 21, 2017 at 19:10
3 Answers 3
That's fine. You have exactly the includes you need, you didn't use using namespace
, and you've used std::cin
correctly.
However, I'd recommend you to use a code formatter next time, since some for your closing braces are misaligned. And if you use braces around a single statement in if
, do the same for else
.
Other than that, you can take a const auto & word
instead of auto w
to remove copies. Also word
is a nicer name than w
. Try to be more verbose, it helps when you read the code a second time.
Since we do not use temp
after the while
, should keep its scope smaller. We can use a for
loop, wrap braces around the while
and temp
's declaration (which does the same), or write a small (inline) function.
We end up with
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> words;
std::cout << "Enter a list of words.\n";
for(std::string temp; std::cin >> temp;){
words.push_back(temp);
}
for(const auto &word : words){
if(word == "idiot" || word == "nonsense" || word == "hyper"){
std::cout << "BlEEP" <<" ";
} else {
std::cout << word << " ";
}
}
}
I've added some whitespace to make the code slightly easier to read. However, our code works well for three words, but what about four, five or even ten? As soon as we have more words than fit in a single line, we probably want to store them in a container.
Exercise
Read the banned words from a file. Use those words to filter the text just like you did.
-
\$\begingroup\$ Thanks for the valuable review. Could you please give suggestion about the container I should use for this purpose. \$\endgroup\$Muhammad Kamal– Muhammad Kamal2017年11月22日 02:20:59 +00:00Commented Nov 22, 2017 at 2:20
-
1\$\begingroup\$ @MuhammadKamal you can use exclusion. You do not know how many words will be in the text file, so both
std::array<std::string>
andstd::string[]
are off. Now we're left withstd::vector
,std::deque
andstd::list
. Since we only need to add elements at the end,std::vector
fits and is usually the best case. However,std::set
is also suitable, since it provides \$\mathcal O(log n)\$ search. Therefore: eitherstd::set
(better asymptotical complexity) orstd::vector
(more likely to have better real world performance) orstd::vector
+std::sort
(probably fastest). \$\endgroup\$Zeta– Zeta2017年11月22日 06:59:26 +00:00Commented Nov 22, 2017 at 6:59
You can use a ternary here.
std::cout << ( ( w == "idiot" || w == "nonsense" || w == "hyper" ) ? "BlEEP" : w ) << " ";
It's arguable whether it's more readable in this case, but it's still handy to remember you can.
Also, FWIW, if you'd have got more std::cout
's, you could've e.g. had using std::cout;
- is a matter of personal choice, but if you're really using one of the imports often, you can remove noise this way.
Note that, IMVHO, having a variable called w
quite OK if you're using it in tight scope (small methods/functions, lambdas, small loop variables etc.), where its function is obvious (as is in this particular case). Don't do that for variables with larger scopes, though!
If you store the bad words separately, it'll be easier to add/remove them, or even take them as input:
const char* badWords[] = {"one", "two", "three"};
Then you can replace them:
for (auto& word : words) {
if (std::find(std::begin(badWords), std::end(badWords), word) != std::end(badWords))
word = "BLEEP";
}