I have the following code prints each unique word and its count from a text file (contains >= 30k words), however it's separating words by whitespace, I had results like so:
how can I modify the code to specify the expected dividers?
template <class KTy, class Ty>
void PrintMap(map<KTy, Ty> map)
{
typedef std::map<KTy, Ty>::iterator iterator;
for (iterator p = map.begin(); p != map.end(); p++)
cout << p->first << ": " << p->second << endl;
}
void UniqueWords(string fileName) {
// Will store the word and count.
map<string, unsigned int> wordsCount;
// Begin reading from file:
ifstream fileStream(fileName);
// Check if we've opened the file (as we should have).
if (fileStream.is_open())
while (fileStream.good())
{
// Store the next word in the file in a local variable.
string word;
fileStream >> word;
//Look if it's already there.
if (wordsCount.find(word) == wordsCount.end()) // Then we've encountered the word for a first time.
wordsCount[word] = 1; // Initialize it to 1.
else // Then we've already seen it before..
wordsCount[word]++; // Just increment it.
}
else // We couldn't open the file. Report the error in the error stream.
{
cerr << "Couldn't open the file." << endl;
}
// Print the words map.
PrintMap(wordsCount);
}
You can use a stream with a std::ctype<char> facet imbue()ed which considers whatever characters you fancy as space. Doing so would look something like this:
#include<locale>
#include<cctype>
struct myctype_table {
std::ctype_base::mask table[std::ctype<char>::table_size];
myctype_table(char const* spaces) {
while (*spaces) {
table[static_cast<unsigned char>(*spaces)] = std::ctype_base::isspace;
}
}
};
class myctype
: private myctype_table,
, public std::ctype<char> {
public:
myctype(char const* spaces)
: myctype_table(spaces)
, std::ctype<char>(table) {
};
};
int main() {
std::locale myloc(std::locale(), new myctype(" \t\n\r?:.,!"));
std::cin.imbue(myloc);
for (std::string word; std::cin >> word; ) {
// words are separated by the extended list of spaces
}
}
This code isn't test right now - I'm typing on a mobile device. I probably misused some of the std::cypte<char> interfaces but something along those lines after fixing the names, etc. should work.
As you expect the forbidden characters at the end of the found word you can remove them prior to push the word into wordsCount:
if(word[word.length()-1] == ';' || word[word.length()-1] == ',' || ....){
word.erase(word.length()-1);
}
After fileStream >> word;, you can call this function. Take a look and see if it's clear:
string adapt(string word) {
string forbidden = "!?,.[];";
string ret = "";
for(int i = 0; i < word.size(); i++) {
bool ok = true;
for(int j = 0; j < forbidden.size(); j++) {
if(word[i] == forbidden[j]) {
ok = false;
break;
}
}
if(ok)
ret.push_back(word[i]);
}
return ret;
}
Something like this:
fileStream >> word;
word = adapt(word);
Related
I need a program to take a string and replace spaces with increasing numbers.
#include <cstring>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// Get the String
string str = "this essay needs each word to be numbered";
int num = 1;
string x = num;
int i = 0;
// read string character by character.
for (i < str.length(); ++i) {
// Changing the loaded character
// to a number if it's a space.
if (str[i] == ' ') {
str[i] = x;
++num
}
}
// testing outputs
cout << str << endl;
cout << num << endl;
ofstream file;
file.open ("numbered.txt");
file << str;
file.close();
return 0;
}
I had it at the point where it could replace spaces with a letter or symbol and save to a new file but when I tried to make it a number it stopped working. I would need it to say "this1essay2needs3each4word5to6be7numbered
For ease and clarity, change your approach.
Put the string into an istringstream
Extract each space-separated substring and place into an std::vector<string>
Feed the contents of the vector into a stringstream and
use std::to_string(num) to add the numbers between the substrings
e.g.:
std::string str = "this essay needs each word to be numbered";
int num = 1;
std::istringstream istr(str);
std::string temp;
std::vector<std::string> substrs;
while (istr >> temp)
{
substrs.push_back(temp);
}
std::stringstream ostr;
for (auto&& substr : substrs)
{
ostr << substr << std::to_string(num++);
}
Let's break the problem down into parts. We can make a SpaceReplacer object that does the replacement. It has an Output, which it can use as a function to output characters:
template<class Output>
struct SpaceReplacer {
Output output;
int num_spaces;
void input(char c) {
if(c == ' ') {
auto num_as_string = std::to_string(num_spaces);
num_spaces += 1;
for(char digit : num_as_string) {
output(digit);
}
}
else {
output(c);
}
}
};
Every time you input a character, it either outputs the character you input, or it outputs the digits of the number (if the character was a space).
We should write a helper function to make SpaceReplacers:
template<class Output>
SpaceReplacer<Output> makeReplacer(Output output_func) {
return SpaceReplacer<Output>{output_func, 0};
}
Reading one string, returning new string
It's now easy to write a function that replaces spaces in a string.
std::string replaceSpaces(std::string const& input) {
std::string output_string;
// We output chars by appending them to the output string
auto output_func = [&](char c) { output_string += c; };
auto replacer = makeReplacer(output_func);
for(char c : input) {
replacer.input(c);
}
return output_string;
}
Reading input from file, replacing spaces and returning a string
Because we wrote a really generic SpaceReplacer class, we can modify the function so that it'll read input directly from a FILE*
std::string replaceSpaces(FILE* file) {
std::string output_string;
auto output_func = [&](char c) { output_string += c; };
auto replacer = makeReplacer(output_func);
while(true) {
int input_char = fgetc(file);
if(input_char == EOF) {
break;
}
replacer.input(input_char);
}
return output_string;
}
Reading input from one file, immediately appending it to different file with spaces replaced
We can also read directly from one file, and output directly to another file, with no delay. This might be useful if you were processing a very large amount of data.
void replaceSpaces(FILE* input_file, FILE* output_file) {
auto output_func = [=](char c) { fputc(c, output_file); };
auto replacer = makeReplacer(output_func);
while(true) {
int input_char = fgetc(input_file);
if(input_char == EOF) {
break;
}
replacer.input(input_char);
}
}
In this case, you need to use another string for the result.
#include <cstring>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// Get the String
string result, str = "this essay needs each word to be numbered qwe qwe wqe qwe qwe qwe q";
int num = 0;
int i;
// read string character by character.
for (i=0; i < str.length(); i++) {
// Changing the loaded character
// to a number if it's a space.
if (str[i] == ' ')
result+=std::to_string(++num);
else
result+=str[i];
}
// testing outputs
cout<<result<<endl;
cout<<num;
ofstream file;
file.open ("numbered.txt");
file << result;
file.close();
return 0;
}
You have to replace it with a character, not by a number.
str[i] = num+'0';
I would like to make a program that asks for text (a paragraph with several words) that would be separated by commas.
To transform the text and add a tag between the two, like to format the text to html text
Example:
word1, word2, word3
to
<a> word1 </a>, <a> word2 </a>, <a> word3 </a>
So I started doing this code but I do not know how to continue. How can I test the text to find the front of the word? I imagine with ASCII tests?
Maybe with a table that will test every case ?
I do not necessarily ask the complete answer but maybe a direction to follow could help.
#include <iostream>
#include <iomanip>
#include <string> //For getline()
using namespace std;
// Creating class
class GetText
{
public:
string text;
string line; //Using this as a buffer
void userText()
{
cout << "Please type a message: ";
do
{
getline(cin, line);
text += line;
}
while(line != "");
}
void to_string()
{
cout << "\n" << "User's Text: " << "\n" << text << endl;
}
};
int main() {
GetText test;
test.userText();
test.to_string();
system("pause");
return 0;
}
The next thing you would need to do is to split your input by a deltimeter (in your case ',') into a vector and later combine everything with pre and posfixes. C++ does not support splitting by default, you would have to be creative or search for a solution like here.
If you want to keep it really simple, you can detect word boundaries by checking two characters at a time. Here's a working example.
using namespace std;
#include <iostream>
#include <string>
#include <cctype>
typedef enum boundary_type_e {
E_BOUNDARY_TYPE_ERROR = -1,
E_BOUNDARY_TYPE_NONE,
E_BOUNDARY_TYPE_LEFT,
E_BOUNDARY_TYPE_RIGHT,
} boundary_type_t;
typedef struct boundary_s {
boundary_type_t type;
int pos;
} boundary_t;
bool is_word_char(int c) {
return ' ' <= c && c <= '~' && !isspace(c) && c != ',';
}
boundary_t maybe_word_boundary(string str, int pos) {
int len = str.length();
if (pos < 0 || pos >= len) {
return (boundary_t){.type = E_BOUNDARY_TYPE_ERROR};
} else {
if (pos == 0 && is_word_char(str[pos])) {
// if the first character is word-y, we have a left boundary at the beginning
return (boundary_t){.type = E_BOUNDARY_TYPE_LEFT, .pos = pos};
} else if (pos == len - 1 && is_word_char(str[pos])) {
// if the last character is word-y, we have a right boundary left of the null terminator
return (boundary_t){.type = E_BOUNDARY_TYPE_RIGHT, .pos = pos + 1};
} else if (!is_word_char(str[pos]) && is_word_char(str[pos + 1])) {
// if we have a delimiter followed by a word char, we have a left boundary left of the word char
return (boundary_t){.type = E_BOUNDARY_TYPE_LEFT, .pos = pos + 1};
} else if (is_word_char(str[pos]) && !is_word_char(str[pos + 1])) {
// if we have a word char followed by a delimiter, we have a right boundary right of the word char
return (boundary_t){.type = E_BOUNDARY_TYPE_RIGHT, .pos = pos + 1};
}
return (boundary_t){.type = E_BOUNDARY_TYPE_NONE};
}
}
int main() {
string str;
string ins_left("<tag>");
string ins_right("</tag>");
getline(cin, str);
// can't use length for the loop condition without recalculating it all the time
for (int i = 0; str[i] != '\0'; i++) {
boundary_t boundary = maybe_word_boundary(str, i);
if (boundary.type == E_BOUNDARY_TYPE_LEFT) {
str.insert(boundary.pos, ins_left);
i += ins_left.length();
} else if (boundary.type == E_BOUNDARY_TYPE_RIGHT) {
str.insert(boundary.pos, ins_right);
i += ins_right.length();
}
}
}
It would be better to use enum class but I forgot the notation. You can also copy to a buffer instead of generating the new string in-place, I was just trying to keep it simple. Feel free to expand it to a class based C++ style. To get your exact desired output, strip the spaces first and add spaces to ins_left and ins_right.
I have data in the following format in a text file. Filename - empdata.txt
Note that there are no blank space between the lines.
Sl|EmployeeID|Name|Department|Band|Location
1|327427|Brock Mcneil|Research and Development|U2|Pune
2|310456|Acton Golden|Advertising|P3|Hyderabad
3|305540|Hollee Camacho|Payroll|U3|Bangalore
4|218801|Simone Myers|Public Relations|U3|Pune
5|144051|Eaton Benson|Advertising|P1|Chennai
I have a class like this
class empdata
{
public:
int sl,empNO;
char name[20],department[20],band[3],location[20];
};
I created an array of objects of class empdata.
How to read the data from the file which has n lines of data in the above specified format and store them to the array of (class)objects created?
This is my code
int main () {
string line;
ifstream myfile ("empdata.txt");
for(int i=0;i<10;i++) //processing only first 10 lines of the file
{
getline (myfile,line);
//What should I do with this "line" so that I can extract data
//from this line and store it in the class object?
}
return 0;
}
So basically my question is how to extract data from a string which has data separated by '|' character and store each data to a separate variable
I prefer to use the String Toolkit. The String Toolkit will take care of converting the numbers as it parses.
Here is how I would solve it.
#include <fstream>
#include <strtk.hpp> // http://www.partow.net/programming/strtk
using namespace std;
// using strings instead of character arrays
class Employee
{
public:
int index;
int employee_number;
std::string name;
std::string department;
std::string band;
std::string location;
};
std::string filename("empdata.txt");
// assuming the file is text
std::fstream fs;
fs.open(filename.c_str(), std::ios::in);
if(fs.fail()) return false;
const char *whitespace = " \t\r\n\f";
const char *delimiter = "|";
std::vector<Employee> employee_data;
// process each line in turn
while( std::getline(fs, line ) )
{
// removing leading and trailing whitespace
// can prevent parsing problemsfrom different line endings.
strtk::remove_leading_trailing(whitespace, line);
// strtk::parse combines multiple delimeters in these cases
Employee e;
if( strtk::parse(line, delimiter, e.index, e.employee_number, e.name, e.department, e.band, e.location) )
{
std::cout << "succeed" << std::endl;
employee_data.push_back( e );
}
}
AFAIK, there is nothing that does it out of the box. But you have all the tools to build it yourself
The C way
You read the lines into a char * (with cin.getline()) and then use strtok, and strcpy
The getline way
The getline function accept a third parameter to specify a delimiter. You can make use of that to split the line through a istringstream. Something like :
int main() {
std::string line, temp;
std::ifstream myfile("file.txt");
std::getline(myfile, line);
while (myfile.good()) {
empdata data;
std::getline(myfile, line);
if (myfile.eof()) {
break;
}
std::istringstream istr(line);
std::getline(istr, temp, '|');
data.sl = ::strtol(temp.c_str(), NULL, 10);
std::getline(istr, temp, '|');
data.empNO = ::strtol(temp.c_str(), NULL, 10);
istr.getline(data.name, sizeof(data.name), '|');
istr.getline(data.department, sizeof(data.department), '|');
istr.getline(data.band, sizeof(data.band), '|');
istr.getline(data.location, sizeof(data.location), '|');
}
return 0;
}
This is the C++ version of the previous one
The find way
You read the lines into a string (as you currently do) and use string::find(char sep, size_t pos) to find next occurence of the separator and copy the data (from string::c_str()) between start of substring and separator to your fields
The manual way
You just iterate the string. If the character is a separator, you put a NULL at the end of current field and pass to next field. Else, you just write the character in current position of current field.
Which to choose ?
If you are more used to one of them, stick to it.
Following is just my opinion.
The getline way will be the simplest to code and to maintain.
The find way is mid level. It is still at a rather high level and avoids the usage of istringstream.
The manual way will be really low level, so you should structure it to make it maintainable. For example your could a explicit description of the lines as an array of fields with a maximimum size and current position. And as you have both int and char[] fields it will be tricky. But you can easily configure it the way you want. For example, your code only allow 20 characters for department field, whereas Research and Development in line 2 is longer. Without special processing, the getline way will leave the istringstream in bad state and will not read anything more. And even if you clear the state, you will be badly positionned. So you should first read into a std::string and then copy the beginning to the char * field.
Here is a working manual implementation :
class Field {
public:
virtual void reset() = 0;
virtual void add(empdata& data, char c) = 0;
};
class IField: public Field {
private:
int (empdata::*data_field);
bool ok;
public:
IField(int (empdata::*field)): data_field(field) {
ok = true;
reset();
}
void reset() { ok = true; }
void add(empdata& data, char c);
};
void IField::add(empdata& data, char c) {
if (ok) {
if ((c >= '0') && (c <= '9')) {
data.*data_field = data.*data_field * 10 + (c - '0');
}
else {
ok = false;
}
}
}
class CField: public Field {
private:
char (empdata::*data_field);
size_t current_pos;
size_t size;
public:
CField(char (empdata::*field), size_t size): data_field(field), size(size) {
reset();
}
void reset() { current_pos = 0; }
void add(empdata& data, char c);
};
void CField::add(empdata& data, char c) {
if (current_pos < size) {
char *ix = &(data.*data_field);
ix[current_pos ++] = c;
if (current_pos == size) {
ix[size -1] = '\0';
current_pos +=1;
}
}
}
int main() {
std::string line, temp;
std::ifstream myfile("file.txt");
Field* fields[] = {
new IField(&empdata::sl),
new IField(&empdata::empNO),
new CField(reinterpret_cast<char empdata::*>(&empdata::name), 20),
new CField(reinterpret_cast<char empdata::*>(&empdata::department), 20),
new CField(reinterpret_cast<char empdata::*>(&empdata::band), 3),
new CField(reinterpret_cast<char empdata::*>(&empdata::location), 20),
NULL
};
std::getline(myfile, line);
while (myfile.good()) {
Field** f = fields;
empdata data = {0};
std::getline(myfile, line);
if (myfile.eof()) {
break;
}
for (std::string::const_iterator it = line.begin(); it != line.end(); it++) {
char c;
c = *it;
if (c == '|') {
f += 1;
if (*f == NULL) {
continue;
}
(*f)->reset();
}
else {
(*f)->add(data, c);
}
}
// do something with data ...
}
for(Field** f = fields; *f != NULL; f++) {
free(*f);
}
return 0;
}
It is directly robust, efficient and maintainable : adding a field is easy, and it is tolerant to errors in input file. But it is way loooonger than the other ones, and would need much more tests. So I would not advise to use it without special reasons (necessity to accept multiple separators, optional fields and dynamic order, ...)
Try this simple code segment , this will read the file and , give a print , you can read line by line and later you can use that to process as you need .
Data : provided bu you : in file named data.txt.
package com.demo;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class Demo {
public static void main(String a[]) {
try {
File file = new File("data.txt");
FileReader fileReader = new FileReader(file);
BufferedReader bufferReader = new BufferedReader(fileReader);
String data;
while ((data = bufferReader.readLine()) != null) {
// data = br.readLine( );
System.out.println(data);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
In console you will get output like this :
Sl|EmployeeID|Name|Department|Band|Location
1|327427|Brock Mcneil|Research and Development|U2|Pune
2|310456|Acton Golden|Advertising|P3|Hyderabad
3|305540|Hollee Camacho|Payroll|U3|Bangalore
4|218801|Simone Myers|Public Relations|U3|Pune
5|144051|Eaton Benson|Advertising|P1|Chennai
This is a simple idea, you may do what you need.
In C++ you can change the locale to add an extra character to the separator list of the current locale:
#include <locale>
#include <iostream>
struct pipe_is_space : std::ctype<char> {
pipe_is_space() : std::ctype<char>(get_table()) {}
static mask const* get_table()
{
static mask rc[table_size];
rc['|'] = std::ctype_base::space;
rc['\n'] = std::ctype_base::space;
return &rc[0];
}
};
int main() {
using std::string;
using std::cin;
using std::locale;
cin.imbue(locale(cin.getloc(), new pipe_is_space));
string word;
while(cin >> word) {
std::cout << word << "\n";
}
}
I have a text file that contains keys and values like this:
keyOne=1
keyTwo=734
keyThree=22.3
keyFour=5
The keys are just lower-case and upper-case letters like in my example. The values are either integers or floats. Each key and value is separated by an equals sign (=). Now I want to read the values into variables I have in my program.
This is the code I have tried to read the values:
(I omitted the part where I store the values in my program's variables, and just print them out now for demonstration.)
std::fstream file(optionsFile, std::fstream::in);
if (file.good()) {
int begin;
int end;
std::string line;
while(std::getline(file, line)) {
// find the position of the value in the line
for (unsigned int i = 0; i < line.length(); i++) {
if (line.at(i) == '=') {
begin = i + 1;
end = line.length();
break;
}
}
// build the string... it starts at <begin> and ends at <end>
const char *string = "";
for (int i = begin; i < end; i++) {
string += line.at(i);
}
// only gibberish is printed in the following line :(
std::cout << "string=" << string << std::endl;
}
}
I don't understand why it won't print the value.. instead only weird stuff or even nothing is printed
Please help this broke my spirit so hard :(
You are using C-style strings (char arrays) without properly allocated memory, and you are just manipulating with the pointer, so you are not appending characters into your string:
// build the string... it starts at <begin> and ends at <end>
const char *string = "";
for (int i = begin; i < end; i++) {
string += line.at(i);
}
Use std::string instead:
/// build the string... it starts at <begin> and ends at <end>
std::string str;
for (int i = begin; i < end; i++) {
str += line.at(i);
}
Or allocate memory by hand, use the proper indexing, terminate the string with '\0' character and don't forget to delete the string after you don't need it anymore:
char *string = new char[end - begin + 1];
int j = 0;
for (int i = begin; i < end; i++) {
string[j++] = line.at(i);
}
// Don't forget to end the string!
string[j] = '\0';
// Don't forget to delete string afterwards!
delete [] string;
So, just use std::string.
Edit Why did you mix C strings and std::string in the first place?
As was already mentioned, native string types in c/c++ do not support straightforward concatenation since they are essentially pointers to some preallocated memory. You should always use std::string when a string is supposed to be mutable.
Btw, think about the following refactoring:
void process_option (const std::string& a_key, const std::string& a_value)
{
std::cout << a_key << " <-- " << a_value << std::endl;
}
void read_options (std::istream& a_in, const char* a_source)
{
int line_n = 0;
std::string line;
while (std::getline(a_in, line))
{
++ line_n;
std::string::size_type p = line. find('=');
if (p == line. npos)
{
// invalid_entry(a_source, line_n);
continue;
}
process_option(
line. substr(0, p), // key
line. substr(p + 1, line. find_first_of("\t\r\n", p + 1)) // value
);
}
}
void read_options (const char* a_filename)
{
std::ifstream file(a_filename);
if (! file)
{
// read_error(a_filename);
return;
}
read_options(file, a_filename);
file. close();
}
void read_options (const std::string& a_filename)
{
read_options(a_filename. c_str());
}
I am currently trying to count the number of words in a file. After this, I plan to make it count the words between two words in the file. For example. My file may contain. "Hello my name is James". I want to count the words, so 5. And then I would like to count the number of words between "Hello" and "James", so the answer would be 3. I am having trouble with accomplishing both tasks.
Mainly due to not being exactly sure how to structure my code.
Any help on here would be greatly appreciated. The code I am currently using is using spaces to count the words.
Here is my code:
readwords.cpp
string ReadWords::getNextWord()
{
bool pWord = false;
char c;
while((c = wordfile.get()) !=EOF)
{
if (!(isspace(c)))
{
nextword.append(1, c);
}
return nextword;
}
}
bool ReadWords::isNextWord()
{
if(!wordfile.eof())
{
return true;
}
else
{
return false;
}
}
main.cpp
main()
{
int count = 0;
ReadWords rw("hamlet.txt");
while(rw.isNextWord()){
rw.getNextWord();
count++;
}
cout << count;
rw.close();
}
What it does at the moment is counts the number of characters. I'm sure its just a simple fix and something silly that I'm missing. But I've been trying for long enough to go searching for some help.
Any help is greatly appreciated. :)
Rather than parse the file character-by-character, you can simply use istream::operator<<() to read whitespace-separated words. << returns the stream, which evaluates to true as a bool when the stream can still be read from.
vector<string> words;
string word;
while (wordfile >> word)
words.push_back(word);
There is a common formulation of this using the <iterator> and <algorithm> utilities, which is more verbose, but can be composed with other iterator algorithms:
istream_iterator<string> input(wordfile), end;
copy(input, end, back_inserter(words));
Then you have the number of words and can do with them whatever you like:
words.size()
If you want to find "Hello" and "James", use find() from the <algorithm> header to get iterators to their positions:
// Find "Hello" anywhere in 'words'.
const auto hello = find(words.begin(), words.end(), "Hello");
// Find "James" anywhere after 'hello' in 'words'.
const auto james = find(hello, words.end(), "James");
If they’re not in the vector, find() will return words.end(); ignoring error checking for the purpose of illustration, you can count the number of words between them by taking their difference, adjusting for the inclusion of "Hello" in the range:
const auto count = james - (hello + 1);
You can use operator-() here because std::vector::iterator is a “random-access iterator”. More generally, you could use std::distance() from <iterator>:
const auto count = distance(hello, james) - 1;
Which has the advantage of being more descriptive of what you’re actually doing. Also, for future reference, this kind of code:
bool f() {
if (x) {
return true;
} else {
return false;
}
}
Can be simplified to just:
bool f() {
return x;
}
Since x is already being converted to bool for the if.
To count:
std::ifstream infile("hamlet.txt");
std::size_t count = 0;
for (std::string word; infile >> word; ++count) { }
To count only between start and stop:
std::ifstream infile("hamlet.txt");
std::size_t count = 0;
bool active = false;
for (std::string word; infile >> word; )
{
if (!active && word == "Hello") { active = true; }
if (!active) continue;
if (word == "James") break;
++count;
}
I think "return nextword;" should instead be "else return nextword;" or else you are returning from the function getNextWord every time, no matter what the char is.
string ReadWords::getNextWord()
{
bool pWord = false;
char c;
while((c = wordfile.get()) !=EOF)
{
if (!(isspace(c)))
{
nextword.append(1, c);
}
else return nextword;//only returns on a space
}
}
To count all words:
std::ifstream f("hamlet.txt");
std::cout << std::distance (std::istream_iterator<std::string>(f),
std::istream_iterator<std::string>()) << '\n';
To count between two words:
std::ifstream f("hamlet.txt");
std::istream_iterator<std::string> it(f), end;
int count = 0;
while (std::find(it, end, "Hello") != end)
while (++it != end && *it != "James")
++count;
std::cout << count;
Try this:
below the line
nextword.append(1, c);
add
continue;