For my computer science class, I was required to write a lexical analysis program that would perform several functions on a std::string
. The assignment required a function for each of the following:
- count number of a certain substring
- count number of words excluding numbers
- count number of unique words (excludes repeated words)
- count number of sentences (by end punctuation)
- average words per sentence
- lexical density as percent (unique word count / word count * 100)
My code is fairly long, but here it is:
#include<iostream>
#include<string>
#include<sstream>
#include<algorithm>
#include<iterator>
#include<vector>
using namespace std;
int substringCount(const string&, const string&);
int wordCount(const string&);
int uniqueWordCount(const string&);
int sentenceCount(const string&);
double wordsPerSentence(const string&);
double lexicalDensity(const string&); // different words / total words * 100
int main() {
string source = ("This is the source text for this program.");
cout << "\"is\" count: " << substringCount(source," is ") << endl;
cout << "Word count: " << wordCount(source) << endl;
cout << "Sentence count: " << sentenceCount(source) << endl;
cout << "Words per sentence: " << wordsPerSentence(source) << endl;
cout << "Lexical density: " << lexicalDensity(source) << endl;
return 0;
}
vector<int> substringIndices(const string& str, const string& sub) { // Find indices of substrings
vector<int> indices = {};
for (unsigned int i = 0; i < str.size(); i++) {
unsigned int t = i;
for (unsigned int j = 0; j < sub.size(); t++, j++) {
if (t >= str.size()) {
break;
}
if (str[t] == sub[j]) {
if (j + 1 == sub.size()) indices.push_back(i);
continue;
} else {
break;
}
}
}
return indices;
}
vector<string> splitByWhitespace(const string& str) { // split by whitespace
vector<string> tokens;
istringstream iss(str); // create istringstream
copy(istream_iterator<string>(iss),istream_iterator<string>(),back_inserter(tokens)); // copy into tokens
return tokens;
}
vector<string> deleteNumbers(const vector<string>& data) {
vector<string> tr = {};
for (unsigned int i = 0; i < data.size(); i++) {
for (char c: data[i]) {
if (string("0123456789").find(c) == -1) continue;
else goto mainLoop;
}
tr.push_back(data[i]);
mainLoop: continue;
}
return tr;
}
int substringCount(const string& str, const string& sub) { // get number of substrings
return substringIndices(str,sub).size();
}
int wordCount(const string& str) { // wordcount (based on whitespace)
return deleteNumbers(splitByWhitespace(str)).size();
}
int uniqueWordCount(const string& str) { // unique word count
vector<string> words = deleteNumbers(splitByWhitespace(str));
sort(words.begin(),words.end()); // sort
words.erase(unique(words.begin(),words.end()),words.end()); // delete extra non-unique words
return words.size();
}
int sentenceCount(const string& str) { // get number of sentences (based on end punctuation)
return substringCount(str,".") + substringCount(str,"?") + substringCount(str,"!");
}
double wordsPerSentence(const string& str) {
return double(wordCount(str)) / double(sentenceCount(str));
}
double lexicalDensity(const string& str) {
return double(uniqueWordCount(str) * 100) / double(wordCount(str));
}
I am relatively new to C++, so if there are any common practices that I am missing it would be great to point them out.