#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
#include <cctype>
/*
This program finds the N most frequently appearing words in a text
after removing stopwords. It demonstrates clean structure, clear
comments, and efficient use of C++ STL containers and algorithms.
*/
// ---------------------------------------------------------------
// Helper: check punctuation
// ---------------------------------------------------------------
bool is_punct(char c) {
return std::ispunct(static_cast<unsigned char>(c));
}
// ---------------------------------------------------------------
// Tokenize text into words (simple whitespace split)
// ---------------------------------------------------------------
std::vector<std::string> tokenize(const std::string& text) {
std::vector<std::string> words;
std::string w;
for (size_t i = 0; i < text.size(); ) {
// Skip whitespace
while (i < text.size() && std::isspace(static_cast<unsigned char>(text[i])))
++i;
// Extract word
w.clear();
while (i < text.size() && !std::isspace(static_cast<unsigned char>(text[i]))) {
w.push_back(text[i]);
++i;
}
if (!w.empty()) {
// Remove punctuation at edges
while (!w.empty() && is_punct(w.front()))
w.erase(w.begin());
while (!w.empty() && is_punct(w.back()))
w.pop_back();
if (!w.empty()) {
// Convert to lowercase
for (char& c : w)
c = std::tolower(static_cast<unsigned char>(c));
words.push_back(w);
}
}
}
return words;
}
// ---------------------------------------------------------------
// Count word frequencies, skipping stopwords
// ---------------------------------------------------------------
std::unordered_map<std::string, int> count_words_frequencies(
const std::vector<std::string>& words,
const std::unordered_set<std::string>& stopwords
) {
std::unordered_map<std::string, int> freq;
for (const auto& w : words) {
if (stopwords.find(w) == stopwords.end()) {
++freq[w];
}
}
return freq;
}
// ---------------------------------------------------------------
// Extract the top N most frequent words
// ---------------------------------------------------------------
std::vector<std::pair<std::string, int>> top_n(
const std::unordered_map<std::string, int>& freq,
std::size_t n
) {
std::vector<std::pair<std::string, int>> items(freq.begin(), freq.end());
// Sort by frequency descending, then alphabetically
std::sort(items.begin(), items.end(),
[](const auto& a, const auto& b) {
if (a.second != b.second)
return a.second > b.second;
return a.first < b.first;
});
if (items.size() > n)
items.resize(n);
return items;
}
// ---------------------------------------------------------------
// Main
// ---------------------------------------------------------------
int main() {
// Example text
std::string text =
"C is a general-purpose programming language created in 1972 by "
"Dennis Ritchie. C gives programmers direct access to the features "
"of CPU. It has been and continues to be used to implement "
"operating systems (especially kernels) and device "
"drivers. C programming language used on computers ranging from "
"supercomputers to microcontrollers and embedded systems.";
// Example stopwords
std::unordered_set<std::string> stopwords = {
"the","is","a","to","how","after","but","this","for","by","in",
"and","can","content","be","you","yes","no","next","about","used",
"access","been","continues"
};
// Tokenize
auto words = tokenize(text);
// Count frequencies
auto freq = count_words_frequencies(words, stopwords);
// Get top N
std::size_t n = 7;
auto topn = top_n(freq, n);
// Print results
std::cout << "Top " << n << " most frequent non-stopwords:\n";
for (const auto& [word, count] : topn) {
std::cout << word << " : " << count << "\n";
}
}
/*
run:
Top 7 most frequent non-stopwords:
c : 3
language : 2
programming : 2
systems : 2
1972 : 1
computers : 1
cpu : 1
*/