Counting individual word lengths in a string - c++

#include <iostream>
#include <string>
#include <cctype>
size_t countwords(const char *);
using namespace std;
int main()
{
char a[] = "Four score and seven years ago";
float sum = 0.0;
char j[10];
string s;
int size = sizeof(a)/sizeof(char);
for(int i = 0; i < size; i++){
if(!isspace(a[i])){
s += a[i];
}
if(isspace(a[i]) and !isspace(a[i + 1])){
cout << s << " " << s.length() << endl;
sum += s.length();
s = "";
}
}
cout << countwords(a);
return 0;
}
size_t countwords( const char *s )
{
size_t count = 0;
while ( *s )
{
while ( isspace( *s )) ++s;
if ( *s ) ++count;
while ( isalnum( *s )) ++s;
}
return ( count );
}
In the main function, I am able to print each word and it's word length. such as four 4, score 5 etc. I am having trouble handling the last word "ago." I don't know how to account for that. Any help would be appreciated.
Output:
Four 4
score 5
and 3
seven 5
years 5
▼ 2
6
and yeah, don't know why that black triangle is in the output but this is the exact output.

The terminating NULL character is not considered whitespace, so your second if condition returns false when it encounters the end of the string.
Seems to me the statements within the for statement can be simplified to
if(!isspace(a[i]) && a[i]){
s += a[i];
} else {
cout << s << " " << s.length() << endl;
sum += s.length();
s = "";
}
Also, breaking the string apart at whitespace can be done easily using an istringstream
char a[] = "Four score and seven years ago";
std::istringstream ss(a);
std::string s;
while(ss >> s) {
std::cout << s << ' ' << s.length() << '\n';
}

The string you try to inspect is one character longer than you expect:
int size = sizeof(a)/sizeof(char);
This size includes the terminating null character. If I were to deal with the assignment I would either operator on char const* and use the C convention of checking against a terminating null character or I would convert the array into a std::string and deal with iterator and check against the end iterator. I also think that the logic you have to check against the end of a word assumes that words are separated by exactly one space.
Your countwords() function seems to deal with the C convention. Your main() function should check against a[i] being null before using !isspace(static_cast<unsigned char>(a[0])): the countwords() works because isspace(0) and isalnum(0) are false. However, just because 0 isn't a space it means it is part of a word. You should also consider the terminating null character a word separator, i.e., the condition to report the length of a word should be
if(!a[i] || isspace(static_cast<unsigned char>(a[i])))

std::string word;
std::istringstream str(a);
while (str >> word) {
sum += str.length();
std::cout << word << ' ' << word.length << '\n';
}

Related

Find subword included input symbol c++

I want to print a subword, after inputting my symbol.
For example like this.
I want input abcdefghijk d
And get efghijk
This is my code body without condition.
#include <iostream>
int main(){
const int n = 21;
char word[n];
std::cin>>word;
char symbol;
std::cin>>symbol;
int i = 0;
char*p = word;
while(word[i]!='\0' && word[i]!=symbol){
// what condition I need to write here?
i++;
std::cout << p <<std::endl;
}
return 0;
}
Thanks for helping))
You need to move your pointer p to the right while the splitting character is not met.
char*p = word;
while(word[i]!='\0' && word[i]!=symbol){
p++;
i++;
}
p++;
std::cout << p << std::endl;
On the first line, your pointer p points to the begining of the word (i.e. on the first char).
Then the while loop tests every char until we find the splitting char. Everytime a character does not match you splitting character, you increase p and make it point to the next character.
However, you would need to increase it one final time after the loop to point after the splitting char.
Note that a shorter way to do is:
char*p = word;
while(word[i]!='\0' && word[i]!=symbol){
i++;
}
p = p + i + 1;
std::cout << p << std::endl;
You could try something like this:
int main()
{
std::string text;
std::cout << "Enter sentence: ";
std::getline(std::cin, text);
char split_char;
std::cout << "Enter subword / split character: ";
std::cin >> split_char;
std::string::size_type split_position = text.find(split_char);
std::string::size_type word_end_position = text.find_first_of(" \t", split_position);
if (word_end_position == std::string::npos)
{
word_end_position = text.length();
}
std::string split_text = text.substr(split_position, word_end_position, split_position);
std::cout << split_text << "\n";
return 0;
}

c++ count words in array

I need to write a function that gets a string and count how many words there are in the string and how many letters. And then calculate the average of it.
A word in a string is a sequence of letters and numbers separated by one or more spaces.
First of all I have to check if the string is correct. The string must contain only lowercase letters, uppercase letters, and numbers only.
i didnt menage to count all sort of words correctly and also my function doesnt count the last letter.
#include <iostream>
using namespace std;
#include <string.h>
#define SIZE 50
float checkString(char string[]) {
float wordCounter = 0;
float letterCounter = 0;
bool isLegit = true;
int i = 0;
while (isLegit) {
if (((string[i] >= 48 && string[i] <= 57) ||
(string[i] >= 65 && string[i] <= 90) ||
(string[i] >= 97 && string[i] <= 122 ))) {
for (int j = 0; j <= strlen(string); j++) {
if ((string[j - 1] != ' ' && string[j] == ' ' &&
string[i + 1] != ' ')
|| j == (strlen(string) - 1)) {
wordCounter++;
}
else if (string[j] != ' ') {
letterCounter++;
cout << string[j];
}
}
cout << " The avareage is : " << (letterCounter /
wordCounter) << endl;
isLegit = false;
}
else {
return -1;
isLegit = false;
}
}
cout << "Number of words " << wordCounter << endl;
cout << "Number of letters " <<letterCounter << endl;
}
int main() {
char string[SIZE];
cout << "please enter a sentence " << endl;
cin.getline(string, SIZE);
checkString(string);
}
Instead of using char[] for strings, I suggest that you use std::string which can grow and shrink dynamically. It's one of the most common types to use in the standard C++ library. You can also make use of stringstreams which lets you put a string inside it and then you can extract the contents of the stringstream using >>, just like when reading from std::cin.
Example with comments in the code:
#include <iostream>
#include <sstream> // std::stringstream
#include <string> // std::string
// use std::string instead of a char[]
float checkString(const std::string& string) {
// put the string in a stringstream to extract word-by-word
std::istringstream is(string);
unsigned words = 0;
unsigned letters = 0;
std::string word;
// extract one word at a time from the stringstream:
while(is >> word) {
// erase invalid characters:
for(auto it = word.begin(); it != word.end();) {
// Don't use magic numbers. Put the character literals in the code so
// everyone can see what you mean
if((*it>='0' && *it<='9')||(*it>='A' && *it<='Z')||(*it>='a' && *it<='z')) {
// it was a valid char
++it;
} else {
// it was an invalid char, erase it
it = word.erase(it);
}
}
// if the word still has some characters in it, make it count:
if(word.size()) {
++words;
letters += word.size();
std::cout << '\'' << word << "'\n"; // for debugging
}
}
std::cout << "Number of words " << words << "\n";
std::cout << "Number of letters " << letters << "\n";
std::cout << "The average number of letters per word is "
<< static_cast<float>(letters) / words << '\n';
return 0.f; // not sure what you are supposed to return, but since the function
// signature says that you should return a float, you must return a float.
}
int main() {
checkString(" Hello !!! World, now let's see if it works. ");
}
I would like to add an additional answer. This answer is based on "more-modern" C++ and the usage of algorithms. You want to solve 3 tasks:
Check, if string is OK and matched to your expectations
Count the number of words in the given string
Count the number of letters
Calculate the ratio of words/letters
For all this you may use existings algorithms from the C++ standard library. In the attached example code, you will see a one-liner for each task.
The statements are somehow very simple, so that I will not explain much more. If there should be a question, I am happy to answer.
Please see here one possible example code:
#include <iostream>
#include <string>
#include <iterator>
#include <regex>
#include <algorithm>
#include <tuple>
#include <cctype>
std::regex re("\\w+");
std::tuple<bool, int, int, double> checkString(const std::string& str) {
// Check if string consists only of allowed values, spaces or alpha numerical
bool stringOK{ std::all_of(str.begin(), str.end(), [](const char c) { return std::isalnum(c) || std::isspace(c); }) };
// Count the number of words
int numberOfWords{ std::distance(std::sregex_token_iterator(str.begin(),str.end(), re, 1), {}) };
// Count the number of letters
int numberOfLetters{ std::count_if(str.begin(), str.end(), isalnum) };
// Return all calculated values
return std::make_tuple(stringOK, numberOfWords, numberOfLetters, static_cast<double>(numberOfWords)/ numberOfLetters);
}
int main() {
// Ask user to input string
std::cout << "Please enter a sentence:\n";
// Get string from user
if (std::string str{}; std::getline(std::cin, str)) {
// Analyze string
auto [stringOk, numberOfWords, numberOfLetters, ratio] = checkString(str);
// SHow result
std::cout << "\nString content check: " << (stringOk ? "OK" : "NOK") << "\nNumber of words: "
<< numberOfWords << "\nNumber of letters: " << numberOfLetters << "\nRatio: " << ratio << "\n";
}
return 0;
}
Of course there are many more other possible solutions. But, because of the simplicity of this solution, I showed this variant.

How to count words in a file?

I'm creating a program that counts how many words there are in a input file. I can't seem to figure out how to make it define a word with either whitespace, a period, a comma, or the beginning or end of a line.
Contents of input file:
hello world ALL is great. HELLO WORLD ALL IS GREAT. hellO worlD alL iS great.
Output should be 15 words meanwhile my output is 14
I've tried adding or's that include periods, commas etc. but it just counts those on top of the spaces as well.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
//Function Declarations
void findFrequency(int A[], string &x);
void findWords(int A[], string &x);
//Function Definitions
void findFrequency(int A[], string &x)
{
//Counts the number of occurences in the string
for (int i = 0; x[i] != '\0'; i++)
{
if (x[i] >= 'A' && x[i] <= 'Z')
A[toascii(x[i]) - 64]++;
else if (x[i] >= 'a' && x[i] <= 'z')
A[toascii(x[i]) - 96]++;
}
//Displaying the results
char ch = 'a';
for (int count = 1; count < 27; count++)
{
if (A[count] > 0)
{
cout << A[count] << " : " << ch << endl;
}
ch++;
}
}
void findWords(int A[], string &x)
{
int wordcount = 0;
for (int count = 0; x[count] != '\0'; count++)
{
if (x[count] == ' ')
{
wordcount++;
A[0] = wordcount;
}
}
cout << A[0] << " Words " << endl;
}
int main()
{
string x;
int A[27] = { 0 }; //Array assigned all elements to zero
ifstream in; //declaring an input file stream
in.open("mytext.dat");
if (in.fail())
{
cout << "Input file did not open correctly" << endl;
}
getline(in,x);
findWords(A, x);
findFrequency(A, x);
in.close();
system("pause");
return 0;
}
The output should be 15 when the result I am getting is 14.
Perhaps this is what you need?
size_t count_words(std::istream& is) {
size_t co = 0;
std::string word;
while(is >> word) { // read a whitespace separated chunk
for(char ch : word) { // step through its characters
if(std::isalpha(ch)) {
// it contains at least one alphabetic character so
// count it as a word and move on
++co;
break;
}
}
}
return co;
}
Here is an approach with a few test cases as well.
The test cases are a series of char arrays with particular strings to test the findNextWord() method of the RetVal struct/class.
char line1[] = "this is1 a line. \t of text \n "; // multiple white spaces
char line2[] = "another line"; // string that ends with zero terminator, no newline
char line3[] = "\n"; // line with newline only
char line4[] = ""; // empty string with no text
And here is the actual source code.
#include <iostream>
#include <cstring>
#include <cstring>
struct RetVal {
RetVal(char *p1, char *p2) : pFirst(p1), pLast(p2) {}
RetVal(char *p2 = nullptr) : pFirst(nullptr), pLast(p2) {}
char *pFirst;
char *pLast;
bool findNextWord()
{
if (pLast && *pLast) {
pFirst = pLast;
// scan the input line looking for the first non-space character.
// the isspace() function indicates true for any of the following
// characters: space, newline, tab, carriage return, etc.
while (*pFirst && isspace(*pFirst)) pFirst++;
if (pFirst && *pFirst) {
// we have found a non-space character so now we look
// for a space character or the end of string.
pLast = pFirst;
while (*pLast && ! isspace(*pLast)) pLast++;
}
else {
// indicate we are done with this string.
pFirst = pLast = nullptr;
}
}
else {
pFirst = nullptr;
}
// return value indicates if we are still processing, true, or if we are done, false.
return pFirst != nullptr;
}
};
void printWords(RetVal &x)
{
int iCount = 0;
while (x.findNextWord()) {
char xWord[128] = { 0 };
strncpy(xWord, x.pFirst, x.pLast - x.pFirst);
iCount++;
std::cout << "word " << iCount << " is \"" << xWord << "\"" << std::endl;
}
std::cout << "total word count is " << iCount << std::endl;
}
int main()
{
char line1[] = "this is1 a line. \t of text \n ";
char line2[] = "another line";
char line3[] = "\n";
char line4[] = "";
std::cout << "Process line1[] \"" << line1 << "\"" << std::endl;
RetVal x (line1);
printWords(x);
std::cout << std::endl << "Process line2[] \"" << line2 << "\"" << std::endl;
RetVal x2 (line2);
printWords(x2);
std::cout << std::endl << "Process line3[] \"" << line3 << "\"" << std::endl;
RetVal x3 (line3);
printWords(x3);
std::cout << std::endl << "Process line4[] \"" << line4 << "\"" << std::endl;
RetVal x4(line4);
printWords(x4);
return 0;
}
And here is the output from this program. In some cases the line to be processed has a new line in it which affects the output by performing a new line when printed to the console.
Process line1[] "this is1 a line. of text
"
word 1 is "this"
word 2 is "is1"
word 3 is "a"
word 4 is "line."
word 5 is "of"
word 6 is "text"
total word count is 6
Process line2[] "another line"
word 1 is "another"
word 2 is "line"
total word count is 2
Process line3[] "
"
total word count is 0
Process line4[] ""
total word count is 0
If you need to treat punctuation similar to white space, as something to be ignored, then you can modify the findNextWord() method to include the ispunct() test of characters in the loops as in:
bool findNextWord()
{
if (pLast && *pLast) {
pFirst = pLast;
// scan the input line looking for the first non-space character.
// the isspace() function indicates true for any of the following
// characters: space, newline, tab, carriage return, etc.
while (*pFirst && (isspace(*pFirst) || ispunct(*pFirst))) pFirst++;
if (pFirst && *pFirst) {
// we have found a non-space character so now we look
// for a space character or the end of string.
pLast = pFirst;
while (*pLast && ! (isspace(*pLast) || ispunct (*pLast))) pLast++;
}
else {
// indicate we are done with this string.
pFirst = pLast = nullptr;
}
}
else {
pFirst = nullptr;
}
// return value indicates if we are still processing, true, or if we are done, false.
return pFirst != nullptr;
}
In general if you need to refine the filters for the beginning and ending of words, you can modify those two places with some other function that looks at a character and classifies it as either a valid character for a word or not.

Reversing char array

When I print out text2 I see that it is definitely not the reverse of the string I gave it and I'm not sure why that is. When I put in "test" I get stuff like "ȍ\2200+". Can I use strncpy on char arrays? Maybe it needs to be done with a loop - not sure. Any help would be appreciated. :)
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char text[79], text2[79];
bool input = true;
while (input) {
cout << "Please give me a line of text to examine: ";
cin.getline(text, 79);
for(int i = 0; i < strlen(text); i++ )
cout << text[i];
// test to see if it is a palindrome
strncpy(text, text2, 80);
reverse(text2, text2 + strlen(text2));
printf("%s", text2); `// when I print this out I get something odd`
if (strcmp(text, text2) == 0)
cout << " is a palindrome!" << endl;
else
cout << " is not a palindrome." << endl;
if (strcmp(text, "END") == 0)
input = false;
else
cout << "\ntype END to exit the program" << endl;
} // end while loop
} // end main
It seems you're using strncpy in a wrong way: you probably want to copy text into text2, not the other way around.
There's a much simpler way to test whether a string is a palindrome, namely:
bool is_palindrome(const char* s, size_t n) {
size_t i, j;
i = 0, j = n-1;
while (i < j && s[i++] == s[j--])
;
return i >= j;
}
Why not use std::vector<char> and std::reverse from <algorithm> to handle your problem?
I would do something like below: (note that I'm using C++11 range-based for loop and auto which you can change to a regular for loop and use std::string line if you don't have a compiler supporting this).
int main()
{
cout << "Please give me a line of text to examine: ";
auto line = ""s;
getline(cin, line);
// Push back every character to the vector
vector<char> vtext;
for (const auto &elem : line)
vtext.push_back(elem);
// Create a copy of the vector<char> and reverse the copy
vector<char> vtext_reversed{vtext};
reverse(begin(vtext_reversed), end(vtext_reversed));
// Print the line reversed
cout << "\nThis is the line reversed: ";
for (const auto &elem : vtext_reversed)
cout << elem;
}
Typically you'll see this reversal technique for char*:
void reverse(char* s) {
if(!s) return;
size_t n = strlen(s);
for(size_t i = 0; i < n/2; ++i) {
char tmp = s[i];
s[i] = s[n - i - 1];
s[n - i - 1] = tmp;
}
}
This will not work, however, with non-ASCII characters. The reason is that non-ASCII characters require multiple bytes to represent.
You will need to use wide characters to handle multi-byte codepoints, but the logic should follow above.

C++ Identifying the Frequency of words occurring in a sentence

What is the best STL to use for this task? I've been using Map,
and I couldn't get it to work. I'm not sure how I am supposed to check the number of same words that occur in the sentence for example:
I love him, I love her, he love her.
So I want the program to prompt the user to enter an integer, lets say i enter 3, the output will be love as the same word occurs 3 times in the sentence. But what method to use if I want to do a program like this?
Currently my program prompts for the user to enter the word, and then it shall return how many time that word occurs, which for word love, is 3. but now i want it the other way round. Can it be done? Using which STL will be better?
I assume you use a map to store the number of occurrences.
Well,you first have to understand this,since you are using a map,the key is unique while the stored data may not be unique.
Consider a map, x
with contents
x["I"]=3
x["Love"]=3
x["C"]=5
There is unique a mapping from the key to the value,and not the other way round,if you want this one to one mapping ,i would suggest a different data structure.If you want to use map,and still search for an element,using STL search function or your own.Or you can write your search function.
search().
map<string,int>::iterator ser;
cin>>check;
for(ser=x.begin();ser!=x.end();++ser)
{
if(ser->second==check)
{
cout<<"Word"<<ser->first<<endl;
break;
}
}
First build the mapping from word to count and then build the reverse multi-mapping from that. Finally, you can determine which words occur with a given frequency:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <utility>
int main()
{
std::string str("I love him, I love her, he love her");
std::istringstream ss(str);
std::istream_iterator<std::string> begin(ss);
std::istream_iterator<std::string> end;
std::map<std::string, int> word_count;
std::for_each(begin, end, [&](const std::string& s)
{
++word_count[s];
});
std::multimap<int, std::string> count_words;
std::for_each(word_count.begin(), word_count.end(),
[&](const std::pair<std::string, int>& p)
{
count_words.insert(std::make_pair(p.second, p.first));
});
auto its = count_words.equal_range(3);
std::for_each(its.first, its.second,
[](const std::pair<int, std::string>& p)
{
std::cout << p.second << std::endl;
});
}
/******************************************************************
Name : Paul Rodgers
Source : HW1.CPP
Compiler : Visual C++ .NET
Action : Program will read in from standard input and determine the
frequency of word lengths found in input. An appropriate
table is also displayed. Maximum word length is 15 characters
words greater then 15 are counted as length 15.
Average word length also displayed.
Note : Words include hyphenated and ones with apostrophes. Words with
apostrophes, i.e. Jim's, will count the apostrophe as part of the
word length. Hyphen is counted if word on same line, else not.
Also an int array is used to hold the number of words with
length associated with matching subscript, with subscript 0
not being used. So subscript 1 corresponds to word length of 1,
subscript 2 to word length of 2 and so on.
------------------------------------------------------------------------*/
#include <iostream>
#include <ctype.h>
#include <iomanip>
using namespace std;
int NextWordLength(void); // function prototypes
void DisplayFrequencyTable(const int Words[]);
const int WORD_LENGTH = 16; // global constant for array
void main()
{
int WordLength; // actual length of word 0 to X
int NumOfWords[WORD_LENGTH] = {0}; // array holds # of lengths of words
WordLength = NextWordLength();
while (WordLength) // continue to loop until no word, i.e. 0
{ // increment length counter
(WordLength <= 14) ? (++NumOfWords[WordLength]) : (++NumOfWords[15]);
WordLength = NextWordLength();
}
DisplayFrequencyTable(NumOfWords);
}
/********************** NextWordLength ********************************
Action : Will determine the length of the next word. Hyphenated words and
words with apostrophes are counted as one word accordingly
Parameters : none
Returns : the length of word, 0 if none, i.e. end of file
-----------------------------------------------------------------------*/
int NextWordLength(void)
{
char Ch;
int EndOfWord = 0, //tells when we have read in one word
LengthOfWord = 0;
Ch = cin.get(); // get first character
while (!cin.eof() && !EndOfWord)
{
while (isspace(Ch) || ispunct(Ch)) // Skips leading white spaces
Ch = cin.get(); // and leading punctation marks
if (isalnum(Ch)) // if character is a letter or number
++LengthOfWord; // then increment word length
Ch = cin.get(); // get next character
if ((Ch == '-') && (cin.peek() == '\n')) //check for hyphenated word over two lines
{
Ch = cin.get(); // don't count hyphen and remove the newline char
Ch = cin.get(); // get next character then on next line
}
if ((Ch == '-') && (isalpha(cin.peek()))) //check for hyphenated word in one line
{
++LengthOfWord; // count the hyphen as part of word
Ch = cin.get(); // get next character
}
if ((Ch == '\'') && (isalpha(cin.peek()))) // check for apostrophe in word
{
++LengthOfWord; // count apostrophe in word length
Ch = cin.get(); // and get next letter
}
if (isspace(Ch) || ispunct(Ch) || cin.eof()) // is it end of word
EndOfWord++;
}
return LengthOfWord;
}
/*********************** DisplayFrequencyTable **************************
Action : Will display the frequency of length of words along with the
average word length
Parameters
IN : Pointer to array holding the frequency of the lengths
Returns : Nothing
Precondition: for loop does not go beyond WORD_LENGTH
------------------------------------------------------------------------*/
void DisplayFrequencyTable(const int Words[])
{
int TotalWords = 0, TotalLength = 0;
cout << "\nWord Length Frequency\n";
cout << "------------ ----------\n";
for (int i = 1; i <= WORD_LENGTH-1; i++)
{
cout << setw(4) << i << setw(18) << Words[i] << endl;
TotalLength += (i*Words[i]);
TotalWords += Words[i];
}
cout << "\nAverage word length is ";
if (TotalLength)
cout << float(TotalLength)/TotalWords << endl;
else
cout << 0 << endl;
}
#include<iostream>
#include<string>
#include<vector>
#include<cstddef>
#include<map>
using std::cout;
using std::cin;
using std::string;
using std::endl;
using std::vector;
using std::map;
int main() {
cout << "Please enter a string: " << endl;
string str;
getline(cin, str, '\n');
size_t str_len = str.size();
cout << endl << endl;
size_t i = 0, j = 0;
bool pop = false;
map<string, int> myMap;
for (size_t k = 0; k < str_len-1; k++) {
if (((k == 0) && isalpha(str[0])) || (!(isalpha(str[k-1])) && isalpha(str[k])))
i = k;
if ( isalpha(str[k]) && !(isalpha(str[k+1])) ) {
j = k;
pop = true;
}
if ( (k == str_len-2) && isalpha(str[k+1]) ) {
j = k+1;
pop = true;
}
if ( (i <= j) && pop ) {
string tmp = str.substr(i, j-i+1);
cout << tmp << '\t';
myMap[tmp]++;
pop = false;
}
}
cout << endl << endl;
map<string, int>::iterator itr, end = myMap.end();
for (itr = myMap.begin(); itr != end; itr++)
cout << itr->first << "\t - - - - - \t" << itr->second << endl;
cout << endl;
return 0;
}