Reading from multiple lines from a txt file in a single iteration - c++

I am working at the moment with linked lists, and my nodes have 4 elements( where each of them is a variable type string). In a .txt file there are groups of text where each group has 4 lines, for example:
This is the first line
This is the second line
This is the third line
This is the fourth line
'\n'
This is the fifth line
This is the sixth line
This is the seventh line
This is the eighth line
and so on and so on...
What I'm trying to achieve is reading the four lines in a single iteration and give them to a node, and let the program iterate until there is no more lines.
So if reading the example above our nodes will be left with;
Node1.string1 = This is the first line;
Node1.string2 = This is the second line;
Node1.string3 = This is the third line;
Node1.string4 = This is the fourth line;
While looking for a way to do this on internet, I found one way you can do this and tell the "ifstream reader" to do a '\n' before the next iteration, but I lost this page and cant seem to find it

Easy enough
while (getline(in, node.string1) &&
getline(in, node.string2) &&
getline(in, node.string3) &&
getline(in, node.string4))
{
...
string dummy;
getline(in, dummy); // skip blank line
}
You can also use in.ignore(std::numeric_limits<std::streamsize>, '\n'); to skip the blank line, but reading into a dummy variable allows you to easily check if the blank line really is blank.

Related

Read elements from a txt file that are separeted by a character

I'am working on a program where there are first names, last names and a numbers on a file and i need to read that information into my program. My actual problem is that there is people who doesnt have a second name or second last name. To solve the issue I started trying to read from a file until a specific character is found, For example:
Robert, Ford Black,208 //Where Robert is the first name, and Ford Black are his two last names
George Richard, Bradford,508 //Where George Richard are both his first names, and Bradford is his only last
name
I am saving this information in three separeted string, one that will store first and second name, first last and second last name and the third one for the numbers.
I'm trying to only use native libraries from c++.
I've been reading that getline(a,b,c) and IStringStream can actually solve my problem but I don't know how to correctly implement it
It's just a matter of using std::getline with a delimiter character to read out of the string stream. See a simplified example (no error checking) below:
for (std::string line; std::getline(std::cin, line); )
{
std::string firstName, lastName;
std::istringstream iss(line);
std::getline(iss, firstName, ','); // A comma delimits end-of-input
iss >> std::ws; // Skip over any whitespace characters
std::getline(iss, lastName); // Read remaining line
std::cout << "First Name: " << firstName << std::endl;
std::cout << "Last Name: " << lastName << std::endl;
}
Note the line iss >> std::ws; using std::ws from <iomanip> is there to eat up extra whitespace characters (which appear after your comma, in your example).
I'm assuming the C++ line comments in the input are only an annotation for this question, and not part of the actual input.
#include<bits/stdc++.h>
using namespace std;
int main()
{
ifstream myfile("files.txt");
string fullname;
while(getline(myfile,fullname,'/')) break; //here im reading till the first / is acquired and the entire string is stored in "fullname"
string firstname,lastname;
size_t pos=fullname.find(',');
firstname=fullname.substr(0,pos); //store the firstname
lastname=fullname.substr(pos+1);// storee the lastname
cout<<firstname<<" "<<lastname;
}
As the question posed was to read names im assuming before the digit if there were a " / " you can read upto the first occurance of /. this will give you the fullname. Then using the substr on the fullname and find the occurance of a comma if at all it exists. All the characters to the left of position of comma will form your first name and the rest on the right of the position of comma will form the lastname.

How can I replace n lines from a file to another file in C++?

I want to replace the last n lines of first.txt with the first n lines of second.txt where n is input by the user. Here's my code:
ofstream myFirst("first.txt", ios:: binary);
ifstream mySecond("second.txt", ios::binary);
int firstFileLine = lineCountFirst;
int count = 0;
while(getline(myFirst, line)){
count++;
if(count >= firstFileLine){
getline(mySecond, line2); // I don't know if it can be written like this
line = line2; // here to replace line to line2
}
}
myFirst.close();
mySecond.close();
The two lines of code with comments are where I am confused about.
Any ideas about how to replace the file?
I want to replace the last n lines of first.txt with the first n lines of second.txt where n is input by the user.
Read first.txt in a std::vector<std::string> line by line. Remove the last n elements from the vector. Write the elements of the vector to a temporary file. Read n lines from second.txt and append them to the temporary file. Unlink first.txt and rename the temporary file you created.

Sorting words on same line in file using sort()

Is there a way to sort words alphabetically that appear on the same line? I know that if I have words on a new line I am able to sort them easily using:
vector<string> file;
string line;
file.clear();
ifstream infile("foo.txt", ios_base::in);
infile.seekg(3);
while (getline(infile, line)){
file.push_back(line);
}
sort(file.begin(), file.end());
ofstream outFile;
outFile.open("foo.txt");
for (const auto &e : file) outFile << e << "\n";
But what if the words were on one line in the file (unseparated by spaces), for example: catapebat(cat ape bat). Is there an easy way to do this in C++? Would I not do the getline bit, since I am only grabbing one line? How would I approach this problem?
Use getline to read a line.
Create an istringstream from the string you just read
Read words from there into a vector<string>
Sort the words in that vector
I would suggest getting a dictionary of words like this and comparing each word with the beginning of the string. If there's a match, you remove that many characters from the beginning of the string and store the word in an array. Repeat this until you get an array that contains all the words and then sort the array alphabetically.
Note: It might be worth going through the entire dictionary and keeping track of each matching word. Once the dictionary has been exhausted, select the longest match as the word before continuing on.

Reading in a file by int, then words

I have a text file that resembles
1 \t words words words words
2 \t words words words words
where the # is the line #, followed by a tab, then followed by random words
I need to read in the int, store it, then skip the \t, and read in each word individually while keeping track of that words position.
I was hoping I could it with getline(file, word, ' '), and a counter but that grabs my first word as 1 \t words.
Any help or suggestions would be much appreciated.
use stringstream and getline,
getline(file, line);
std::stringstream ssline(line);
int num;
ssline >> num;
std::string word;
while(ssline >> word){
// do whatever you want.
}
Assuming that you can't say how many words there are on a line, then the simple answer is to do it in two steps.
Read a whole line into a string with getline
Place that string into a std::istringstream and read the line number and following words from the std::istringstream
then repeat from step 1

String vectors not working as expected with newline and iterators? (C++)

I have a text file made of 3 lines:
Line 1
Line 3
(Line 1, a blank line, and Line 3)
vector<string> text;
vector<string>::iterator it;
ifstream file("test.txt");
string str;
while (getline(file, str))
{
if (str.length() == 0)
str = "\n";
// since getline discards the newline character, replacing blank strings with newline
text.push_back(str);
} // while
for (it=text.begin(); it < text.end(); it++)
cout << (*it);
Prints out:
Line 1
Line 3
I'm not sure why the string with only a newline was not printed out. Any help would be appreciated. Thanks.
Wasn't? Actually, it was! The reason you have a newline after Line 1 is exactly that empty string with newline in it and nothing else. If not for that second line, you'd see Line 1Line 3 as output. (You said it yourself: getline discards newline characters.)
Apparently, the way I understand your intent, you were supposed to implement your output cycle as follows
for (it = text.begin(); it < text.end(); it++)
cout << *it << endl;
That way you add a newline after each string during output. But if so, then you don't need to manually add a \n character to empty strings during reading.
In other words, decide what is it you want to do. At this time it is not clear.
If you want to restore the discarded
newline characters during reading,
you have to do it for all lines,
not just for empty ones.
If you want to add the newline
characters during output, you don't
need to explictly push them into the
read lines at all.
In fact, it is a rather strange idea to literally push the newline characters into your strings. What for? Since you already read and store your text line-by-line, the newline characters can be implied. I.e. you can do the printing as I do it above (with endl), and everything will look as expected.
I think the simple answer here, is that getline() strips the trailing newline whether or not there is content in the string. So the three reads you do are as follows:
"Line 1"
""
"Line 3"
which you transform into:
"Line 1"
"\n"
"Line 3"
which when printed is:
Line 1
Line 3
I'd use something like this:
std::vector<std::string> text;
std::string str;
while (std::getline(infile, str))
text.push_back(str);
std::copy(text.begin(), text.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
You're adding complexity that stops your code from working.