For example, when parsing a text file, some times this file have stuff like this:
keyword a string here
keyword another string
keyword
keyword again a string
Note that the 3th line have an empty string (nothing or white spaces).. The thing is that when you do stringstream>>laststring, and stringstream have an empty string (null or just white space), it will not overwrite the "laststring", it will do nothing. Theres anyway to check this situation before hand? I dont want to create a temp empty string just to check it is still empty after stringstream>>, seems lame.
When you cannot read from stream - its state changes, so when casting to bool, it returns false:
bool read = static_cast<bool>(ss >> laststring);
Or - in if-expr:
if (ss >> laststring)
cout << "Just read: " << laststring;
See example
You can only know after trying to read whether there was something or not. What you might be able to do is to skip whitespace and see if there is a non-space in the next location:
if ((in >> std::ws).peek() != std::char_traits<char>::eof()) {
...
}
Given that empty strings are cheap to create, I wouldn't bother and try read the string. Note, however, that reading from streams isn't line based, i.e., in your case above you need to split the lines first or use something like std::getline() to read the second part of line.
You can use getline, to read a line from the file. Then, copy the line into a string stream and read words from the string stream one at a time. The streams will automatically stop reading when they run out of lines / words.
// open file
std::ifstream fin("text.txt");
// 'iterate' through all the lines in the file
unsigned lineCount = 1;
std::string line;
while (std::getline(fin, line))
{
// print the line number for debugging
std::cout << "Line " << lineCount << '\n';
// copy line into another stream
std::stringstream lineStream(line);
// 'iterate' through all the words in the line
unsigned wordCount = 1;
std::string word;
while (lineStream >> word)
{
// print the words for debugging
std::cout << '\t' << wordCount++ << ' ' << word << '\n';
}
}
You need to include iostream, fstream, sstream and string.
For checking if string is empty, use foo.size() == 0.
For checking if string stream is empty fooStream.rdbuf()->in_avail() == 0
Related
I need to sort the input text document and write it into another test document. so that lines with an even number of words delete every second word, and lines with an odd number of words remain unchanged. The sorting should be performed as a function, the first pointer to the input of the string and the second pointer to the output.
I did the input and output, tried to do a sorting to begin with without a function, but nothing worked. can you tell me what I did not do the rule?
Example:
Input.txt
I do not like to go to school or study
I like to play games
Output.txt
I not to to or
I like to play games
string in, out;
cin >> in;
cin >> out;
ifstream input(in);
string str;
ofstream output(out);
string st;
while (getline(input, str))
{
do
{
int i = count(str.cbegin(), str.cend(), ' ');
if (i % 2 == 0)
st.append(str);
else
st.append(" ");
i++;
}
while (input);
output << st << endl;
}
The std::stringstream will be your friend.
Read about it here and especially for the useful std::istringstream here.
What can we do with this thing? We can put a string into it and then use the extraction operator >> like with any other stream.
So, counting words will become very simple. We read a line from the file as a std::string and then put it into a std::istringstream, Then we extract dummy words and increase a counter until the reading fails. Then we have the number of words.
Example:
// We read one line. Count the number of words
// Put the string in a stringstream to easily extract words
std::istringstream iss(line);
// Counter for words
unsigned int wordCount{};
// Dummy word
std::string tempWord{};
// Do the counting
while (iss >> tempWord) ++wordCount;
The stream tries too read until it cannot read any more (the stream is empty) and then sets a failbit. The failure of any stream can be checked with its bool operator or the !-operator. The while loop expects a boolean. And the extraction operation iss >> tempWord will return a reference to the stream and then its bool operator will be called and used as condition.
OK, understood, we can now count words. Next step is to skip words.
This is similar simple. In case of even number of words in a string, we will read always 2 words in a loop and simply throw the second one away.
Like this
std::string usedWord{};
// Read 2 words, ignore the second
while (iss >> usedWord >> tempWord)
result += (usedWord + ' ');
There are of course many other possible ways to solve that, but maybe the below solution can give you an idea.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
int main() {
// First read the input filename
std::cout << "\nPlease enter the path for the input file:\n";
std::string inputFileName{};
std::getline(std::cin, inputFileName);
// next read the output filename
std::cout << "\nPlease enter the path for the output file:\n";
std::string outputFileName{};
std::getline(std::cin, outputFileName);
// Open now both files. If one file cannot be opened, then no need tocontinue
// Open input file and check, if it could be opened
std::ifstream inputFileStream(inputFileName);
if (inputFileStream) {
// Input file could be opened without error.
// Now open output file and check, if it could be opened
std::ofstream outputFileStream(outputFileName);
if (outputFileStream) {
// Now, both input and output file streams are open
// Read lines
std::string line{};
while (std::getline(inputFileStream, line)) {
// We read one line. Count the number of words
// Put the string in a stringstream to easily extract words
std::istringstream iss(line);
// Counter for words
unsigned int wordCount{};
// Dummy word
std::string tempWord{};
// Do the counting
while (iss >> tempWord) ++wordCount;
// if the number of words is even then
if ((wordCount % 2) == 0) {
// Rinitialize stringstream
iss.clear(), iss.str(line);
// Here we store the resulting sentence
std::string result{};
// Now extract the word that we will keep and the other one that we will throw away
std::string usedWord{};
// Read 2 words, ignore the second
while (iss >> usedWord >> tempWord)
result += (usedWord + ' ');
// Write result to output
outputFileStream << result << '\n';
}
else
outputFileStream << line << '\n';
}
}
else std::cerr << "\n*** Error: could not open output file '" << outputFileName << "'\n\n";
}
else std::cerr << "\n*** Error: could not open input file '" << inputFileName << "'\n\n";
}
I'm having trouble figuring out how to get newlines to display when outputting text to cmdPrompt. The .text file is something like this:
"Roses are red
violets are blue
sugar is sweet
and so are you"
And my code for the loop is:
#define newLn "\n"
ifstream ins; //these two are near the top where the programs opens the file
string aString;
while(ins >> aString){
if(aString != newLn){
cout << aString << ' ';
}
else
cout << endl;
}
It reads in the text fine but it just displays it like this:
Roses are red violets are blue sugar is sweet and so are you
I don't know how to display it exactly like it is in the text file (with the newlines after each statement. I know you can just do while(nextCharacter != newLn) for reading in by chars but strings got me stumped.
When you use formatted extraction functions, such as:
while(ins >> aString){
you lose all the whitespace characters that are present in the stream.
In order to preserve the whitespaces, you can use std::getline.
std::string line;
while ( getline(ins, line) )
{
std::cout << line << std::endl;
}
If you need to extract the individual tokens from the lines, you can process the lines of text using std::istringstream.
std::string line;
while ( getline(ins, line) )
{
cout << line << std::endl;
std::istringstream str(line);
std::string token;
while ( str >> token )
{
// Use token
}
}
You are using the "fstream extraction operator" to read in the file content. So keep in mind the operator doesn't read take in account white spaces and new lines but it consider them to be the end of the word. So instead use std::getline.
while(std::getline(ins, aString) )
std::cout << aString << std::endl;
i'm trying to get my program to read a string and then output each word on an individual line. When I call this function it is not printing the last word of the sentence. I have not been able to find an answer to this problem.
For example:
Input:
Hello there my friend
Output:
Hello
there
my
Here is my code:
istream& operator >> (istream& in, FlexString& input) {
std::string content;
while (std::getline (in,content,' ')) {
cout << content << endl;
}
return in;
}
I'm new to C++ so this may be dumb, but I tried adding another cout call to print content on the next line after the while loop but it won't print it for some reason.
getline didn't skip the last word. It's still waiting for you to finish it. You selected the space character (' ') as the delimiter, so getline is going to read until if finds a space (not a tab or a newline), or until the input stream ends. Your loop isn't going to stop at the end of the line either, like you seem to be expecting. It is going to keep reading until the stream ends.
If you want to read a single line, and then separate the line word by word, then just call getline once, with the \n delimiter (which is the default). Then use an istringstream to separate the resulting string word by word.
std::string line;
std::getline(in, line);
std::istringstreaam iss(line);
std::string content;
while (iss >> content)
std::cout << content << std::endl;
This code always prints the last line of the file. I expected it to print all the text, one line at a time, from the file. Any idea why it doesn't work?
string filename;
cout << "File to read: ";
cin >> filename;
ifstream afile;
afile.open(filename.c_str());
string line;
while(!afile.eof()) {
getline(afile, line);
cout << line;
}
afile.close();
Trying it this way does the same thing:
for (string line; getline(afile, line);) {
cout << line;
}
Maybe this is an issue with my terminal? This works...
for (string line; getline(afile, line);) {
cout << line << endl;
}
The problem is that only the last line is printed. Correct?
I suggest that you add std::endl in your while loop. It can make the issue more clear. Sometimes the output can be confusing.
You can also check the line-delimiting character in your input file. '\n' is the default delimiter for getline. If a different character is used, specify it as getline's 3rd parameter.
From cplusplus.com:
If the delimiter is found, it is extracted and discarded, i.e. it is
not stored and the next input operation will begin after it.
Since your original code snippet doesn't insert any extra newlines itself, there is nothing making the output to the terminal go to the next line. When the output runs out of horizontal space what happens next is up to the terminal. I'm not sure what terminal you're using but in your case, it just wraps the cursor back to the first character on that line without a linefeed. On a windows command shell, it just wraps around to the next line.
Also note that:
while(!afile.eof()) {
getline(afile, line);
cout << line;
}
is a common antipattern. As already pointed out, more appropriate would be:
while(getline(afile, line)) {
cout << line << '\n';
}
The file stream only becomes false after you've reached eof and try to read from it.
I have a question regarding reading a *.txt file with C++. I'm trying to read only the part of data between some specific sign like [start] and [end].
How I can do that?
I know how to open and read the whole file but I don't know how to read only a part of it with such requirements.
Use std::string and std::getline to filter out lines and go from there. Example:
std::ifstream input("someText.txt");
std::string line;
unsigned int counter = 0;
while (std::getline(input, line))
{
std::cout << "line " << counter << " reads: " << line << std::endl;
counter++;
}
Furthermore you can use the substr() method of the std::string class to filter out sub strings. You can also tokenize words (instead of lines) with std::getline using the optional third argument, which is the tokenizer. Example:
std::ifstream input("someText.txt");
std::string word;
unsigned int counter = 0;
while (std::getline(input, word, ' '))
{
std::cout << "word #" << counter << " is: " << word << std::endl;
counter++;
}
The way to go here would be to read word by word until you get the wanted start tag, then you read and save all words until the end tag is read.
If you are creating that .txt file by yourself, create it in a structured way, keeping offsets and size of different blocks in the beginning. if so, you can read the offset of required block of data from the beginning and jump to there using fseek (or similar). Otherwise, you have to read word by word.