// 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 <string>
#include <vector>
std::string input_word();
int main()
{
usingnamespace 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';
}
cout << "Please enter output file name\n";
string oname;
cin >> oname;
ofstream ofs{ oname };
try
{
if (!ofs)
{
error("can't open output file ", oname);
}
}
catch (const runtime_error &e)
{
cerr << "runtime error: " << e.what() << '\n';
}
string word = input_word();
vector<string> words;
while (getline(ifs, word))
{
words.push_back(word);
}
}
std::string input_word()
{
usingnamespace std;
string word;
cin >> word;
return word;
}
I'm having trouble figuring out how to read a line with getline() and then match the word with the input word. Do I make another string variable to hold the string being read into and match that with the input word?
And this is the file I have (let me know if it's good enough for this program):
To check if a word is in the line you read with getline you need to use the string::find method. Also you need a counter for the line number. However the vector is not needed. Just output the line to the output file if it contains the search word.
But wait a minute. I'm using an output file, but the exercise doesn't say anything about using an output file. I'll take the output file out and just send the program's output to the screen.
Edit: Would this be fine?
1 2 3 4 5 6 7 8 9 10 11 12
string word = input_word();
while (!ifs.eof())
{
string line;
int line_num = 1;
getline(ifs, line, ' ');
size_t found = line.find(word);
if (!found)
{
line_num++;
}
}
If so, how do I get the correct line number output the words in that line?
You'd have to increment line_num irrespective of whether or not word is found within line, also if you don't use the vector method you'd have to check for word boundaries or you could get false positives as in the example below:
1 2 3 4 5 6 7 8 9
#include <iostream>
#include <string>
int main()
{
std::string line = "Ripoff marketing is bad for consumers";
std::string key = "of";
std::cout << line.find(key);
}
edit: mention case-sensitivity, punctuation as well
And this is the file I have (let me know if it's good enough for this program):
You probably should have some words that repeat in some of the different lines.
Since getline() also seems to require a delimiter, I'll just pass in a space character.
No getline() doesn't require a delimiter. Did you find and read any documentation for this function? The third parameter to this function is optional (this parameter has a default value of '\n' (the new line character)). Since you want a full line are you sure you want to use a space as the third parameter.
The third argument is optional, but it says "delim" on the prototypes for the versions that need three arguments.
It's a newline as the default third argument, right? So if you provide something other than a newline, you can get a whole line. But the versions of the function that take only two arguments should read a whole line, too.
@Gunnerfunner: If I use a space as a delimiter, won't it look for spaces to know where a word ends? Or am I looking at it wrong?
It's a newline as the default third argument, right?
Correct.
So if you provide something other than a newline, you can get a whole line.
No, you get everything up to the delimiter, so if you use a space character as the delimiter you will get all of the characters until a space character is encountered, not necessarily a line, more likely a single word.
But the versions of the function that take only two arguments should read a whole line, too.
Yes the versions of getline() that take two parameters will retrieve a complete line because it uses the new line character as a delimiter.
EDIT:
By the way the two argument getline(stream&, string&) just calls the three argument version supplying the new line character as the delimiter.
If I use a space as a delimiter, won't it look for spaces to know where a word ends?
But be careful if you use the space character as a delimiter getline() will only use a single space as the delimiter, it will not detect any of the other whitespace delimiters, such as the tab character or the new line character. If you want a single word you would be better off using the extraction operator>> instead of getline().
Okay, I'll use getline() with two arguments, then. But how should I count the number of lines (and is the code I already have for that good enough?)? That and how do I get all of the words on the line so I can print them out?
If I put that inside a condition checking if the current line contains the input word (I'd put the update to the counter variable after the condition), would it work? Seems like it might.
// 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 <string>
std::string input_word();
void print_line(std::istream &is);
int main()
{
usingnamespace 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';
}
print_line(ifs);
keep_window_open();
}
std::string input_word()
{
usingnamespace std;
string word;
cin >> word;
return word;
}
void print_line(std::istream &is)
{
usingnamespace std;
string line;
cout << "Input word to search for: ";
string word = input_word();
size_t line_counter = 1;
size_t i = 0;
while (getline(is, line))
{
if (word[i] == line[i])
{
cout << line_counter << ": " << line << '\n';
}
line_counter++;
i++;
}
}
Here's the most recent output:
Please enter input file name
words_input.txt
Input word to search for: fly
2: fly float glide gliding floating flying floats flies glider gliders
Please enter a character to exit
k
Press any key to continue . . .
The problem is that you only compare the first char of word with the first char of line.
Then the while loop goes to the next line...
Line 2 starts with f and so it's printed but the other lines are not.
I would move the check for word to a seperate function like: bool contains(const string& haystack, const string& needle
In this way you can test it separately.
Or I could use string::find()? What string should call it with (like if I call it as str1.find(str2);, which string should str1 be?)? Is it like this? line.find(word);
Thanks. It worked for me, though I make some changes. I used string::find() in contains_word() to see if the word was there, and I didn't use trim() because I don't know how to fix the warning message I get when I use it (something about an unsafe use of bool).
and I didn't use trim() because I don't know how to fix the warning message I get when I use it (something about an unsafe use of bool).
Then post the complete error message along with the code that actually generated the warnings and perhaps someone can point you in the right direction. A big part of programming is learning to understand what your compiler is telling you.
EDIT:
By the way the following is a horrible use of exceptions, IMO. Since you're in main() why not just print the error message and return to the operating system?