How to NOT use \n as delimiter in getline() - c++

I'm trying to read in lines from a plain text file, but there are line breaks in the middle of sentences, so getline() reads until a line break as well as until a period. The text file looks like:
then he come tiptoeing down and stood right between us. we could
a touched him nearly. well likely it was minutes and minutes that
there warnt a sound and we all there so close together. there was a
place on my ankle that got to itching but i dasnt scratch it.
My read-in code:
// read in sentences
while (file)
{
string s, record;
if (!getline( file, s )) break;
istringstream ss(s);
while (ss)
{
string s;
if (!getline(ss, s, '.')) break;
record = s;
if(record[0] == ' ')
record.erase(record.begin());
sentences.push_back(record);
}
}
// output sentences
for (vector<string>::size_type i = 0; i < sentences.size(); i++)
cout << sentences[i] << "[][][][]" << endl;
The purpose of the [ ][ ][ ][ ] was to check if linebreaks were used as delimiters and were not just being read into the string. The output would look like:
then he come tiptoeing down and stood right between us.[][][][]
we could[][][][]
a touched him nearly.[][][][]
well likely it was minutes and minutes that[][][][]
there warnt a sound and we all there so close together.[][][][]
there was a[][][][]
place on my ankle that got to itching but i dasnt scratch it.[][][][]

What exactly is your question?
You're using getline() to read from the file stream with a newline delimiter, then parsing that line with a getline() using the istringstream is and a delimiter '.'. So of course you're getting your strings broken at both the new line and the '.'.

getdelim() works like getline(), except that a line delimiter other than newline can be specified as the delimiter argument. As with getline(), a delimiter character is not added if one was not present in the input before end of file was reached.
ssize_t getdelim(char **restrict lineptr, size_t *restrict n, int delimiter, FILE *restrict stream);

Related

I cant end getline when see ' - ' character, can someone help me getline() ifstream in c++

ifstream InPut;
ofstream OutPut;
InPut.open("/Users/apple/Documents/Lập trình C++/OOP/Tập tin/Test1/Test1/FileIn.txt",ios_base::in);
string str, mssv;
getline(InPut,str);
InPut.seekg(1,ios_base::cur);
getline(InPut,mssv);
InPut.close();
cout<<""<<str<<"/"<<mssv;
return 0;
FileIn.txt:
Nguyen Xuan Sang-1520159
I just want to read "Nguyen Xuan Sang", but my code reads in all of FileIn.txt.
Computers can't read your mind. You never told it to read to the "-", so the computer has no way of knowing at all if you want to read until a space, line break, or something else.
getline() defaults to using a nextline as the delimiter, which in your case seems to cause it to read the whole file.
To tell getline() to read until a "-", specify the character as the third argument like this:
getline(InPut, str, '-');

c++ parsing comments using string buffer

I am trying to write a code that will read in c++ files, recognize comments, and store each words in comment into a vector. My problem is that I cannot find a way to read in a single line comment.
My logic is this: If the first character in a string buffer is '/' check for second char to determine whether it is a single line or multi-line comments. If the comment is single line, read in every word delimited by whitespace until I hit new line character '\n'. If the comment is multi-line, I will read in every word until I hit another */. so the code snippet for this is,
while(!input.eof())
{
string buffer;
input >> buffer;
//check if the line is comment
if(buffer[0] == '/')
{
//single line comment
if(buffer[1] == '/')
{
//read in until I hit newlineChar, and store all words into vector
while(buffer[0] != '\n')
{
input >> buffer;
vector.add(buffer);
}
}
//multiline comment
else if(buffer[1] == '*')
{
//read until I hit */ and store all words into vector
while(buffer[buffer.size()-1] != '*' && buffer[buffer.size()] != '/')
{
input >> buffer;
vector.add(buffer);
}
}
}
}
The Problem is with my understanding of new line character. I don't quite understand how string processes the new line char. I'm assuming the string treats new line char as another delimiter just like whitespace. But even in such case, there has to be a way to recognize end of a line using string. What could be a solution to this? Any input is appreciated.
EDIT: Taking advice of user4581301, I added the while loop that reads till the end of file. And to note the problem of lines having extraction operator followed by // like
std::cout<<"//this is not a comment.";
And one way I can think of to avoid this is to read in entire line using getline and char*.
char buffer[200];
input.getline(buffer,200);
string tempStr = buffer;
vector.add(tempStr);
In this case, how can I break individual string stored in vector into words?

I filed my vector from a text file and it wont cout as one line. How can I do this?

Long story short I need my vector to cout as a single line without creating its own new lines for my program to work correctly. the text file i read into the vector was
laptop#a small computer that fits on your lap#
helmet#protective gear for your head#
couch#what I am sitting on#
cigarette#smoke these for nicotine#
binary#ones and zeros#
motorcycle#two wheeled motorized bike#
oj#orange juice#
test#this is a test#
filled the vector using the loop:
if(myFile.is_open())
{
while(getline(myFile, line, '#'))
{
wordVec.push_back(line);
}
cout << "words added.\n";
}
and printed it using this:
for(int i = 0; i < wordVec.size(); i++)
{
cout << wordVec[i];
}
and it outputs as such:
laptopa small computer that fits on your lap
helmetprotective gear for your head
couchwhat I am sitting on
cigarettesmoke these for nicotine
binaryones and zeros
motorcycletwo wheeled motorized bike
ojorange juice
testthis is a test
my program works if I manually input the words and add them to my data structure but if added from the vector which is filled via text file, half of the program doesnt work. before anyone says asks for a better description of the problem, all I need to know is how to fill the vector so that it will output as a single line.
You code getline(myFile, line, '#') reads everything up to end-of-file or the next '#' into line - that includes any newlines. So, as you read text file content...
laptop#a small computer that fits on your lap#
helmet#protective gear for your head#
...which you could also think of as...
"laptop#a small computer that fits on your lap#\nhelmet#protective gear for your head#"
...line takes on successive values...
"laptop"
"a small computer that fits on your lap"
"\nhelmet"
...etc....
Note the newline in "\nhelmet".
There are many ways to avoid or correct this, such as...
while ((myFile >> std::skipws) and getline(myFile, line, '#'))
...
...or...
if (not line.empty() and line[0] == '\n')
line.erase(0, 1);
...or (as Barry suggests in comments)...
while (getline(myFile, line))
{
std::istringstream iss(line);
std::string field;
while (getline(iss, field, '#'))
...
}
while(getline(myFile, line, '#'))
Here, you told std::getline to use the '#' character instead of a newline, '\n', as a delimiter.
So, this simply means that std::getline will no longer think there's anything special about '\n'. It's just another character that std::getline() will keep reading, looking for the next #.
So, you end up reading newline characters into your individual strings, and then outputing them to std::cout, as part of the strings you've printed.

Reading a text file in c++

string numbers;
string fileName = "text.txt";
ifstream inputFile;
inputFile.open(fileName.c_str(),ios_base::in);
inputFile >> numbers;
inputFile.close();
cout << numbers;
And my text.txt file is:
1 2 3 4 5
basically a set of integers separated by tabs.
The problem is the program only reads the first integer in the text.txt file and ignores the rest for some reason. If I remove the tabs between the integers it works fine, but with tabs between them, it won't work. What causes this? As far as I know it should ignore any white space characters or am I mistaken? If so is there a better way to get each of these numbers from the text file?
When reading formatted strings the input operator starts with ignoring leading whitespace. Then it reads non-whitespace characters up to the first space and stops. The non-whitespace characters get stored in the std::string. If there are only whitespace characters before the stream reaches end of file (or some error for that matter), reading fails. Thus, your program reads one "word" (in this case a number) and stops reading.
Unfortunately, you only said what you are doing and what the problems are with your approach (where you problem description failed to cover the case where reading the input fails in the first place). Here are a few things you might want to try:
If you want to read multiple words, you can do so, e.g., by reading all words:
std::vector<std::string> words;
std::copy(std::istream_iterator<std::string>(inputFile),
std::istream_iterator<std::string>(),
std::back_inserter(words));
This will read all words from inputFile and store them as a sequence of std::strings in the vector words. Since you file contains numbers you might want to replace std::string by int to read numbers in a readily accessible form.
If you want to read a line rather than a word you can use std::getline() instead:
if (std::getline(inputFile, line)) { ... }
If you want to read multiple lines, you'd put this operation into a loop: There is, unfortunately, no read-made approach to read a sequence of lines as there is for words.
If you want to read the entire file, not just the first line, into a file, you can also use std::getline() but you'd need to know about one character value which doesn't occur in your file, e.g., the null value:
if (std::getline(inputFile, text, char()) { ... }
This approach considers a "line" a sequence of characters up to a null character. You can use any other character value as well. If you can't be sure about the character values, you can read an entire file using std::string's constructor taking iterators:
std::string text((std::istreambuf_iterator<char>(inputFile)),
std::istreambuf_iterator<char>());
Note, that the extra pair of parenthesis around the first parameter is, unfortunately, necessary (if you are using C++ 2011 you can avoid them by using braces, instead of parenthesis).
Use getline to do the reading.
string numbers;
if (inputFile.is_open())//checking if open
{
getline (inputFile,numbers); //fetches entire line into string numbers
inputFile.close();
}
Your program does behave exactly as in your description : inputFile >> numbers; just extract the first integer in the input file, so if you suppress the tab, inputFile>> will extract the number 12345, not 5 five numbers [1,2,3,4,5].
a better method :
vector< int > numbers;
string fileName = "text.txt";
ifstream inputFile;
inputFile.open(fileName.c_str(),ios_base::in);
char c;
while (inputFile.good()) // loop while extraction from file is possible
{
c = inputFile.get(); // get character from file
if ( inputFile.good() and c!= '\t' and c!=' ' ) // not sure of tab and space encoding in C++
{
numbers.push_back( (int) c);
}
}
inputFile.close();

Tokenization of a text file with frequency and line occurrence. Using C++

once again I ask for help. I haven't coded anything for sometime!
Now I have a text file filled with random gibberish. I already have a basic idea on how I will count the number of occurrences per word.
What really stumps me is how I will determine what line the word is in. Gut instinct tells me to look for the newline character at the end of each line. However I have to do this while going through the text file the first time right? Since if I do it afterwords it will do no good.
I already am getting the words via the following code:
vector<string> words;
string currentWord;
while(!inputFile.eof())
{
inputFile >> currentWord;
words.push_back(currentWord);
}
This is for a text file with no set structure. Using the above code gives me a nice little(big) vector of words, but it doesn't give me the line they occur in.
Would I have to get the entire line, then process it into words to make this possible?
Use a std::map<std::string, int> to count the word occurrences -- the int is the number of times it exists.
If you need like by line input, use std::getline(std::istream&, std::string&), like this:
std::vector<std::string> lines;
std::ifstream file(...) //Fill in accordingly.
std::string currentLine;
while(std::getline(file, currentLine))
lines.push_back(currentLine);
You can split a line apart by putting it into an std::istringstream first and then using operator>>. (Alternately, you could cobble up some sort of splitter using std::find and other algorithmic primitaves)
EDIT: This is the same thing as in #dash-tom-bang's answer, but modified to be correct with respect to error handing:
vector<string> words;
int currentLine = 1; // or 0, however you wish to count...
string line;
while (getline(inputFile, line))
{
istringstream inputString(line);
string word;
while (inputString >> word)
words.push_back(pair(word, currentLine));
}
Short and sweet.
vector< map< string, size_t > > line_word_counts;
string line, word;
while ( getline( cin, line ) ) {
line_word_counts.push_back();
map< string, size_t > &word_counts = line_word_counts.back();
istringstream line_is( line );
while ( is >> word ) ++ word_counts[ word ];
}
cout << "'Hello' appears on line 5 " << line_word_counts[5-1]["Hello"]
<< " times\n";
You're going to have to abandon reading into strings, because operator >>(istream&, string&) discards white space and the contents of the white space (== '\n' or != '\n', that is the question...) is what will give you line numbers.
This is where OOP can save the day. You need to write a class to act as a "front end" for reading from the file. Its job will be to buffer data from the file, and return words one at a time to the caller.
Internally, the class needs to read data from the file a block (say, 4096 bytes) at a time. Then a string GetWord() (yes, returning by value here is good) method will:
First, read any white space characters, taking care to increment the object's lineNumber member every time it hits a \n.
Then read non-whitespace characters, putting them into the string object you'll be returning.
If it runs out of stuff to read, read the next block and continue.
If the you hit the end of file, the string you have is the whole word (which may be empty) and should be returned.
If the function returns an empty string, that tells the caller that the end of file has been reached. (Files usually end with whitespace characters, so reading whitespace characters cannot imply that there will be a word later on.)
Then you can call this method at the same place in your code as your cin >> line and the rest of the code doesn't need to know the details of your block buffering.
An alternative approach is to read things a line at a time, but all the read functions that would work for you require you to create a fixed-size buffer to read into beforehand, and if the line is longer than that buffer, you have to deal with it somehow. It could get more complicated than the class I described.