Ignoring the blank spaces at the end of a file - c++

Is there a way to add a line at the end of a file even if there are blank lines at the end of it? Here's an example code:
void add(fstream &inputfile, int x, int y)
{
inputfile.clear();
inputfile.seekg(0, ios::end);
while(??) //while last line is blank space
inputfile.seekg(-1, ios::end); //go back one line
inputfile << x << "\t" << y << endl; //when while's finished add the new one
inputfile.seekp(0);
}
In order to accomplish this output:
Input file:
1 2
2 3
Wrong output file:
1 2
2 3
3 4
Correct output file:
1 2
2 3
3 4
Is it possible to be done this way? What should be put inside that while loop? The code should be working even if there aren't any blank spaces so we have to use a while statement instead of a simple if one. If it can't be done this way do you have any other suggestions?

Go to just before the end of the file. Then use a loop that peeks at the next character (reads it without advancing). If it's a newline it goes back a character and repeats the loop. When you get to the last non-newline character, seek ahead 2 bytes, to skip over that character and the newline.
inputfile.seekg(-1, ios::end);
while(inputfile.peek() == '\n') {
inputfile.seekg(-1, ios::cur);
}
inputfile.seekg(2, ios::cur);

Related

Getline skips last semicolon (csv) c++

I have a really big csv file with 10 comma seperated values in each line, at the end of each line is a \n.
Now I have a row with just semicolons. The amount of values corresponds to how many comma seperated values are in the other lines
5696;Neusser Strasse;49;1;50670;Neustadt-Nord;18.09.1990;um;1890;Wohn- u. Geschäftshaus
;;;;;;;;;
5698;Richard-Wagner-Strasse;18;1;50674;Neustadt-Süd;18.09.1990;;1905;Wohnhaus
When I now start to run my program, it gets the "5698" from the 3rd line as the last value of the 2nd line, so what I get is this:
0 Denkmalnummer: 5696
1 Strasse: Neusser Strasse
2 Nummer: 49
3 Bezirk: 1
4 PLZ: 50670
5 Ort: Neustadt-Nord
6 unter Schutz: 18.09.1990
7 Baujahr Zusatz: um
8 Baujahr: 1890
9 Kurzbezeichnung: Wohn- u. Geschäftshaus
****************
0 Denkmalnummer:
1 Strasse:
2 Nummer:
3 Bezirk:
4 PLZ:
5 Ort:
6 unter Schutz:
7 Baujahr Zusatz:
8 Baujahr:
9 Kurzbezeichnung: 5698
****************
0 Denkmalnummer: Richard-Wagner-Strasse
1 Strasse: 18
2 Nummer: 1
3 Bezirk: 50674
4 PLZ: Neustadt-S├╝d
5 Ort: 18.09.1990
6 unter Schutz:
7 Baujahr Zusatz: 1905
8 Baujahr: Wohnhaus
9 Kurzbezeichnung: 5699
This continues and messes up the proper alignment of the data.
My major code looks like this (via getline the file's data is stored in a vector):
if (denkmallist.is_open()) {
if (counter < 1) {
while (getline(denkmallist, line)) {
stringstream ss(line);
while (getline(ss, line, ';')) {
ausgelesenes.push_back(line);
counter++;
daten.push_back(ausgelesenes);
ausgelesenes.clear();
}
}
}
else{
while (getline(denkmallist, line)){
ausgelesenes.push_back(line);
}
daten.push_back(ausgelesenes);
ausgelesenes.clear();
}
}
and the code which then displays the results looks like this:
for(int x=0, y=semis; x<=semi2+2, y<daten.size(); x++, y++){
if (x > semi2-1){
x = 0;
cout << '\n' << "****************" << '\n' << endl;
}
cout << x << " " << daten[x][0] << ": " << daten[y][0] << endl;
}
Semi represents the amount of entires.
I would be very happy if someone could help me out :)
The inner loop uses the call to getline to decide when it has finished parsing the text string that was read by the outer call to getline. That's okay, but you have to watch out for extraneous failures.
For the first line, the inner loop runs ten times; once for each field that ends with a ; and once more to read the remaining text.
For the second line, there is no text after the last ;. After the ninth time through the loop, getline sees no text and no delimiter, so it concludes that it's at the end of the input. The call fails, and the inner loop exits after reading only nine inputs instead of the expected ten.

How does cin works in a while loop when the inputs are given in a single line with white spaces?

Consider this small piece of code:
#include <iostream>
#include<stdio.h>
using namespace std;
int main() {
int a;
while(true){
cin>>a;
cout<<a;
}
return 0;
}
Input
1 2 3 5 7 23
Output
125723
How I thought it will run is:
First iteration
1. Reads the first input ie '1' and stops reading further, right after reading the whitespace.
2.Prints the value 1.
Second iteration
1. Again asks for new input
2. Print that in the second line
But that doesn't happen instead it reads the elements we gave after space
First iteration:
Peek at next character in the stream. It's a digit ('1'), so read it.
Peek at next character in the stream. It's not a digit (' '), so don't read it; store 1 in a and return from >>.
(Output 1.)
Second iteration:
Peek at next character in the stream. It's whitespace (' '), so read and ignore it.
Peek at next character in the stream. It's a digit ('2'), so read it.
Peek at next character in the stream. It's not a digit (' '), so don't read it; store 2 in a and return from >>.
(Output 2.)
And so on ...
The point is that >> does not care about lines. cin is one long input stream of characters (some of which may be '\n'). The only thing you can do is read more characters (and then maybe decide that you don't want to do anything with them).
cin is not necessarily connected to a keyboard. The program that started you gets to decide where cin reads from. It can be a file, a network socket, or interactive user input. In the latter case, reading from cin may block until the user types more input, but it will never cause input to just be dropped.
If you want a sane user interface, always read whole lines and process them afterwards:
std::string line;
while (std::getline(std::cin, line)) {
// do stuff with line
}

Vector is not acting as expected

I am trying to open a text file and pass the lines of the text file to a vector. The first digit in each line is the size of the vector and since I do not know the end point of the text file I am using a while loop to find the end. The idea is that I can take a text file and run a merge sort on it. So, for example:
3 5 4 9
5 0 2 6 8 1
sorted it would be become:
4 5 9
0 1 2 6 8
The problem I am having is that when I sort a vector that is larger than the prior vector (as in the example) I do not get output. It is probably something simple that I just have over looked. I am pretty sure the issue is in the code below. Thanks for any pointers.
while (!file.eof())
{
int size;
file >> size;
vector<int> myVector(size);
int n = 0;
while (n < size && file >> myVector[n])
{
++n;
}
sort(myVector);
for (int j = 0; j < size; ++j)
{
if (file.eof()) break;
cout << myVector[j] << ' ';
}
cout << '\n';
}
The problem is this line:
if (file.eof()) break;
Once you've read the last line of the file, file.eof() will be true. So the first time through the loop that's supposed to print the sorted vector, you break out of the loop and don't print anything. It has nothing do with whether the vector is larger than the previous vector, it's just a problem with the last line of the file. The fix is to get rid of that unnecessary line.
You also need to change the main loop. while (!file.eof()) is the wrong way to loop over a file's contents (see the linked questions for full explanations). Use:
int size;
while (file >> size) {
...
}
because of the line :
if(file.eof()) break;
if you get to eof your program wont print anything since you break the printing loop on its first iteration
for instance - if there are no chars after 8 in your example - you wont get output ,but even a single space can change that
besides that - is there any chance or cases that your sorting function clears a vector ? or changes it ?

Issue reading a file

i am creating a program to read the .dxf file of autodesk.
i am encountering a problem while reading strings.
when i use :
string acad;
fstream f;
f.open(name);
f >> acad
if the string is "chamfer" it works perfect.
but if the string is "a & b" it is able to read only upto a.
since the file format follows a pattern i am using while loop.
example from a file:
9 //loop 1
$DWGCODEPAGE //loop 1
3 //looop 1
ANSI_1252 //looop 1
9 //loop 2
$LASTSAVEDBY //loop 2
1 //loop 2
sam & tom //loop 2
9 //loop 3
$INSBASE //loop 3
10 //loop 3
0.0 //loop 3
as you can see sometimes there may not be any space as in "ANSI_1252" & sometimes there may be spaces as in "sam & tom".
how can i generalise the code so that the whole string in a line is stored along with the spaces, if any.
please forget about the spaces in the beginning of each line, i am using ws for that.
thank you!
>> operator reads words delimited by space, when used with a string parameter. If you want to read lines of characters, you should use getline() instead.

C++ adding a carriage return at beginning of string when reading file

I have two questions:
1) Why is my code adding a carriage return at the beggining of the selected_line string?
2) Do you think the algorithm I'm using to return a random line from the file is good enough and won't cause any problems?
A sample file is:
line
number one
#
line number two
My code:
int main()
{
srand(time(0));
ifstream read("myfile.dat");
string line;
string selected_line;
int nlines = 0;
while(getline(read, line, '#')) {
if((rand() % ++nlines) == 0)
selected_line = line;
}
// this is adding a \n at the beginning of the string
cout << selected_line << endl;
}
EDIT: OK, what some of you suggested makes a lot of sense. The string is probably being read as "\nmystring". So I guess my question now is, how would i remove the first \n from the string?
What you probably want is something like this:
std::vector<std::string> allParagraphs;
std::string currentParagraph;
while (std::getline(read, line)) {
if (line == "#") { // modify this condition, if needed
// paragraph ended, store to vector
allParagraphs.push_back(currentParagraph);
currentParagraph = "";
else {
// paragraph continues...
if (!currentParagraph.empty()) {
currentParagraph += "\n";
}
currentParagraph += line;
}
}
// store the last paragraph, as well
// (in case it was not terminated by #)
if (!currentParagraph.empty()) {
allParagraphs.push_back(currentParagraph);
}
// this is not extremely random, but will get you started
size_t selectedIndex = rand() % allParagraphs.size();
std::string selectedParagraph = allParagraphs[selectedIndex];
For better randomness, you could opt for this instead:
size_t selectedIndex
= rand() / (double) (RAND_MAX + 1) * allParagraphs.size();
This is because the least significant bits returned by rand() tend to behave not so randomly at all.
Because you don't specify \n as a delimeter.
Your "random" selection is completely wrong. In fact, it will always select the first line:
rand() % 1 is always 0.
There is no way to uniformly select a random line without knowing the number of lines present.
In addition, why are you using # as a delimiter? Getline, by default, gets a line (ending with \n).
The newlines can appear from the second line that you print. This is because, the getline function halts on seeing the # character and resumes the next time it is called from where it left of i.e. a character past the # which as per your input file is a newline. Read the C FAQ 13.16 on effectively using rand().
One suggestion is to read the entire file in one go, store the lines in a vector and then output them as required.
Because # is your delimeter, the \n that exists right after that delimeter will be the beginning of your next line, thus making the \n be in front of your line.
1) You're not adding a \n to selected_line. Instead, by specifying '#' you are simply not removing the extra \n characters in your file. Note that your file actually looks something like this:
line\n
number one\n
#\n
line number two\n
<\pre>
So line number two is actually "\nline number two\n".
2) No. If you want to randomly select a line then you need to determine the number of lines in your file first.
You could use the substr method of the std::string class to remove the \n after you decide which line to use:
if ( line.substr(0,1) == "\n" ) { line = line.substr(1); }
As others have said, if you want to select the lines with uniform randomness, you'll need to read all the lines first and then select a line number. You could also use if (rand() % (++nlines+1)) which will select line 1 with 1/2 probability, line 2 with 1/2*1/3 probability, etc.