reading multiple lines of text until blank line - c++

I'm working on a program that gets the user to enter text until the program reads a blank line. So far, I have this:
#include <iostream>
#include <cstring>
int main() {
string text;
cout << "Enter Your Text: " << endl;
getline(cin,text);
cout << "Text" << endl;
return 0;
}
But, this only outputs my text as a line and not individual lines, like I would like it to. And then there is the part when it reads a blank line that signifies the end of the user input.
I read that getline() gets all user input, but how do I display it as individual lines?
I read that I may have to use a tokenizer, but I am confused as to how they work, and how you actually write one. I was thinking of using a vector, or some kind of array, but vectors are the only ones I am sort of familiar with.
And I'm not quite sure how to get the program to stop at a blank line. I was thinking maybe a while loop, but what would go in the parenthesis, and how would that be combined with getting the user input?
What I'm basically trying to figure out is how to modify my code to output the user input as lines rather than one whole statement, and to stop getting user input when the user enters a blank line.

Try something like this:
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> text;
std::string line;
std::cout << "Enter Your Text: " << std::endl;
while (std::getline(std::cin, line) && !line.empty())
text.push_back(line);
std::cout << "You entered: " << std::endl;
for (auto &s : text)
std::cout << s << std::endl;
return 0;
}

Related

One extra line being read in file handling

I am trying to get the number of lines and words from a text file in c++. But one extra line is being read by compiler.
#include <iostream>
#include<fstream>
using namespace std;
int main(void)
{
ifstream f;
string name;
char a;
int line, words;
line = 0;
words = 0;
f.open("file.txt");
while (f) {
f.get(a);
if (a == '\n')
{
line++;
words++;
}
if (a == ' ')
{
words++;
}
}
f.close();
cout << "Number of words in file : " << words << endl;
cout << "Numbers of lines in the file : " << line << endl;
}
OUTPUT:-
Number of words in file : 79
Numbers of lines in the file : 3
file.txt:-
This C++ Program which counts the number of lines in a file. The program creates an input file stream, reads a line on every iteration of a while loop, increments the count variable and the count variable is printed on the screen.
Here is source code of the C++ program which counts the number of lines in a file. The C++ program is successfully compiled and run on a Linux system. The program output is also shown below.
I am puzzled why one extra line is being read. Kindly help.
You are not checking if f.get() succeeds or fails. When it does fail, a is not updated, and you are not breaking the loop yet, so you end up acting on a's previous value again. And then the next loop iteration detects the failure and breaks the loop.
Change this:
while (f) {
f.get(a);
...
}
to this instead:
while (f.get(a)) {
...
}
That being said, you are also not taking into account that the last line in a file may not end with '\n', and if it does not then you are not counting that line. And also, you are assuming that every line always has at least 1 word in it, as you are incrementing words on every '\n' even for lines that have no words in them.
I would suggest using std::getline() to read and count lines, and std::istringstream to read and count the words in each line, eg:
#include <fstream>
#include <sstream>
#include <string>
#include <cctype>
using namespace std;
int main(void)
{
ifstream f;
string line, word;
int lines = 0, words = 0;
f.open("file.txt");
while (getline(f, line))
{
++lines;
std::istringstream iss(line);
while (iss >> word) {
++words;
}
}
f.close();
cout << "Number of words in file : " << words << endl;
cout << "Numbers of lines in the file : " << line << endl;
}
It is because you do not check in what state is stream that f.get(a) returns.

Multiset: Problem with multiset adding more than one version of a word and cannot handle large amounts of text

Update and fixed: I have fixed the problem causing the error message- Huge thanks to user PaulMcKenzie for helping me understand what the error message was telling me!- When my program encountered a letter with a mark above it (diacritical marks I think they are called), it crashed. I have adjusted my code to account for these and now it doesn't crash at all! Another huge thanks to user ihavenoidea for helping me understand multisets! My program is now working the way it's supposed to!
Original post:
****I am VERY new to C++ so any and all help is appreciated!****
Ok, so I'm trying to use multiset to sort words so I can see how many times a word appears in a text. First, my program accepts a file, then it reads the words and takes out any punctuation, then it puts it into a multiset. After this, it is supposed to put the results into a text file the user names themselves.
My first issue is that the multiset seems to be creating more than one element for the same word (For example: in one of my tests I saw a(4) listed in the text document 3 times in a row instead of one time).
My Second issue is that when I try to read in large text documents (I'm using John Colliers story "Bottle Party" http://ciscohouston.com/docs/docs/greats/bottle_party.html to test it) my program completely crashes but doesn't crash when I test it with a smaller text document (small being with say about 5-10 lines of text). I'm using Visual Studios and (once again I'm new to Visual Studios also) I don't know what the error message is trying to tell me but it says:
After selecting retry:
As always, any and all help is greatly appreciated.
Code here:
#include <iostream>
#include <string> //for strings
#include <fstream> //for files
#include <set> //for use of multiset
using namespace std;
string cleanUpPunc(string);
//Global variables
multiset <string> words; //will change back to local variable later
int main() {
//Starting variables
string fileName1 = "", fileName2 = "", input = "", input2 = ""; //To hold the input file and the file we wish to print data to if desired
ifstream fileStream; //gets infor from file
//Program start
cout << "Welcome to Bags Program by Rachel Woods!" << endl;
cout << "Please enter the name of the file you wish to input data from: ";
getline(cin, fileName1);
//Trys to open file
try {
fileStream.open(fileName1);
if (!fileStream) {
cerr << "Unable to open file, please check file name and try again." << endl;
system("PAUSE");
exit(1);
}
while (fileStream >> input) {
input2 = cleanUpPunc(input); //sends the input word to check for punctation
words.insert(input2); //puts the 'cleaned up' word into the multiset for counting
}
fileStream.close();
//Sends it to a text document
cout << "Please name the file you would like to put the results into: ";
getline(cin, fileName2);
ofstream toFile; //writes info to a file
//Code to put info into text file
toFile.open(fileName2);
if (toFile.is_open()) {
multiset<string>::iterator pos;
for (pos = words.begin(); pos != words.end(); pos++) {
toFile << *pos << " " << words.count(*pos) << endl;
}
toFile.close();
cout << "Results written to file!" << endl;
}
else {
cout << "Could not create file, please try again." << endl;
}
}catch (exception e) {
cout << "Stop that. ";
cout << e.what();
}
cout << "Thanks for using this program!" << endl;
system("PAUSE");
return 0;
}
string cleanUpPunc(string maybe) {
//Takes out puncuation from string
//Variables
string takeOut = maybe;
//Method
for (int i = 0, len = maybe.size(); i < len; i++) {
if (ispunct(takeOut[i])) {
takeOut.erase(i--, 1);
len = takeOut.size();
}
}
return takeOut;
}

Ignore tabs and line breaks in user input using getline

I'm writing a program that takes user input using getline(I must use getline) and spits it back out to the screen. It is also supposed to ask again if the input was blank. I'm having trouble with handling input that has multiple line breaks and tabs.
I've gotten it to almost work but it's looping through a few times and I can't figure out how to fix it/do it better. Here's the code:
string name;
while(true)
{
cout << "What is your name?" << endl;
getline(cin, name, '\n');
if (!name.empty())
{
break;
}
}
cout << "Hello " << name << "!" << endl;
return 0;
Here's the input:
\n
\n
John\n
Doe\n
The output I want is supposed to look like this:
What is your name?
Hello John Doe!
My output looks like this:
What is your name?
What is your name?
What is your name?
Hello John!
It's possible I don't understand your requirements, but if all you want to do is to collect a first and last name from the user on separate lines (while ignoring any tabs), you can do it like this.
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::string first;
std::string last;
std::cout << "What is your name?\n";
while (first.empty())
{
std::getline(std::cin, first);
// remove all tabs from input
first.erase(std::remove(first.begin(), first.end(), '\t'), first.end());
}
while (last.empty())
{
std::getline(std::cin, last);
// remove all tabs from input
last.erase(std::remove(last.begin(), last.end(), '\t'), last.end());
}
std::string name = first + " " + last;
std::cout << "Hello, " << name << "!\n";
return 0;
}
Your user will be allowed to hit return/enter and tab until they are delirious. Until std::getline() gets some non-tabbed input it doesn't matter how many newlines or tabs happen. From your question this seems like what you want. You can find more information on the STL algorithm that I used to remove tabs with std::remove here.

How to print output in a file after a few empty lines

What I want to do here, is print the word "hello", first at the beginning, then skip some lines, then print it again in the file. The number of lines I need to skip is specified by the user. The file may or may not be empty, and if it's not empty, I don't want to change data on lines other than I need to print. If the file is empty, then it has to skip empty lines and still print after some lines.
Here is my code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main(){
ifstream f1("temp.txt");
ofstream f2("temp.txt");
int r;
cout << "Enter number of lines to skip:" ;
cin >> r;
f2 << "hello";
string org = "";
while(--r){
getline(f1, org);
cout << "org: "<< endl;
}
int pos = f1.tellg();
cout << "pos: " << pos << endl;
f2.seekp(pos, f2.beg);
f2 << "hello";
}
The output I receive when I input r=3, for example, and the file is empty:
org:
org:
pos: -1
Also, the file remains empty. No output.
tellg() does not seem to work.
Anyone has any idea what to do here?
First of all, don't read and write to the same file. Files are opened in different modes so this won't work. But aside from that it is also better practice to parse your input, then operate on it in memory and write out the desired result. so open the file, read what is of interest (you can store a map with the lines that are interesting, or read the whole thing into memory) then do your operations on it, and write out the result.

Looping over file, only get one line

Say we have a text file with this contents:
dogs
cats
bears
trees
fish
rocks
sharks
these are just words separated by newline chars. I am trying to create a Node.js addon. The Addon will read through a file and replacing matching lines with a blank line. Say I pass my program a regex that matches /trees/. If I pass the file to my C++ program it will read + write to the file, and result in:
dogs
cats
bears
fish
rocks
sharks
Right now, the problem is it's not looping through all the lines in the file. I get the feeling that's opening the file in append mode and therefore just starting at the end of the file? I can't tell. Anyway, I want to edit the file in place, not truncate and re-write or replace the whole file, because this will interrupt processes which are tailing the file.
Here's the code:
#include <nan.h>
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
void Method(const Nan::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(Nan::New("world").ToLocalChecked());
}
void Init(v8::Local<v8::Object> exports) {
fstream infile("/home/oleg/dogs.txt");
if(infile.fail()){
cerr << " infile fail" << endl;
exit(1);
}
int pos = 0;
string line;
int count = 0;
while (getline(infile, line)){
// we only seem to loop once, even though the file has 7 or 8 items
count++;
long position = infile.tellp();
cout << "tellp position is " << position << endl;
string str(line);
int len = str.length();
cout << " => line contains => " << line << endl;
cout << " line length is " << len << endl;
std::string s(len, ' '); // create blank string of certain length
infile << s; // write the string to the current position
pos = pos + len;
cout << "pos is " << pos << endl;
}
cout << " => count => " << count << endl;
infile.close();
exports->Set(Nan::New("hello").ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(Method)->GetFunction());
}
NODE_MODULE(hello, Init)
to compile the code you might need to use Node.js tooling, which is
node-gyp rebuild
If you want to help and want to try to compile the code, then let me know, because you may need more info. But I am a new C++ newb and I think someone can help me figure it out without compiling/running the code. Thanks.
To answer your question on why you only read one line of the input file:
Your first write to the file likely sets the eofbit on the stream, so the second getline() attempt will think it has no more to read.
The comment from #RSahu describes the simplest way to do this for text files.