PPP2 Chapter 11 Exercise 2

Pages: 12
> I used string::find() in contains_word() to see if the word was there

The problem with using string::find() (as it has been used) is this:
if we try to list all the lines containing the word 'template',
lines containing the word 'contemplated' would also be part of the list.


> I guess it's just a typo,

Yes. Corrected now.
@Thomas1965: Yeah, the warning I got was the one that says I made an unsafe use of bool in an operation.

@JLBorges: Thanks for fixing it. It does make more sense that way and it works in the program, too.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// chap11ex2.cpp : Defines the entry point for the console application.
// Osman Zakir
// 2 / 28 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 11 Exercise 2
// Exercise Specifications:
/**
 * Write a program that given a file name and a word outputs each line that
 * contains that word together with the line number. Hint: getline().
 */

#include "../../cust_std_lib_facilities.h"
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <cctype>
#include <sstream>
#include <string>

std::string input_word();
void print_line(std::istream &is);
bool contains_word(std::string &line, std::string &word);
std::string replace_punct(std::string &str);
std::string to_lower(std::string &str);
std::string trim(std::string &str);

int main()
{
	using namespace std;
	cout << "Please enter input file name\n";
	string iname;
	cin >> iname;
	ifstream ifs{ iname };
	try
	{
		if (!ifs)
		{
			error("can't open input file ", iname);
		}
	}
	catch (const runtime_error &e)
	{
		cerr << "runtime error: " << e.what() << '\n';
		keep_window_open();
		return 1;
	}

	print_line(ifs);
	keep_window_open();
}

std::string input_word()
{
	using namespace std;
	string word;
	cin >> word;
	return word;
}

void print_line(std::istream &is)
{
	using namespace std;
	cout << "Input word to search for: ";
	string line;
	string word = input_word();
	size_t line_counter = 1;
	while (getline(is, line))
	{
		if (contains_word(line, word))
		{
			cout << line_counter << ": " << line << '\n';
		}
		++line_counter;
	}
}

bool contains_word(std::string &line, std::string &word)
{
	using namespace std;
	word = trim(replace_punct(to_lower(word)));
	istringstream ist{ replace_punct(to_lower(line)) };
	string token;
	while (ist >> token)
	{
		if (token == word)
		{
			return true;
		}
	}
	return false;
}

std::string replace_punct(std::string &str)
{
	using namespace std;
	string result;
	for (char c : str)
	{
		result += ispunct(c) ? ' ' : c;
	}
	return result;
}

std::string to_lower(std::string &str)
{
	for (char &c : str)
	{
		c = tolower(c);
	}
	return str;
}

std::string trim(std::string &str)
{
	using namespace std;
	while (!str.empty() && isspace(str.back()))
	{
		str.pop_back();
	}
	size_t pos = 0;
	while (pos < str.size() && isspace(str[pos]))
	{
		++pos;
	}
	return str.substr(pos);
}
If it interests you, try extending this so that if the word being searched for is "template", it would also match lines that contain words like "templates" or "templated".
Stemming: https://en.wikipedia.org/wiki/Stemming

The Porter Stemming Algorithm works well when the text is in English (or American).
https://tartarus.org/martin/PorterStemmer/
Topic archived. No new replies allowed.
Pages: 12