Getline skips last semicolon (csv) c++ - 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.

Related

C++ [std::regex] trying to match only numbers with spaces in between

I'm working on a card game in C++ where I want to get some user input via getline(). The input needs to be in this specific format:
"1 2 3 4 5 6"
The range of numbers is 1-11 and each number must be seperated with a space. The user is putting in index numbers for a vector. Say he writes "1 2 3" and hits enter, position 0, 1 and 2 are being adressed by the vector.
I'm also open for any other recommendations considering the design decision to let the user input the vector (or essentially their card's) position.
The player cards are displayed in this format "1 blue" and are stored as strings in a vector. I figured it is too much hassle for the user to input the whole card name, so I chose to use the vector index.
Below is the code snippet of my regex string. It works, kinda. It just pushes the whole string in the vector, missing the 10. But I don't need 1 vector element like this: "1 2 3 4", I need 4 vector elements with every number being one element.
Things that shouldn't match:
"1234567"
"abcdef"
"12 34 567 32"
If you need any further context, I will gladly provide so.
Thanks in advance
int main()
{
int i = 0;
std::regex rx("([[:digit:]]\\s)+([[:digit:]]\\s)+");
std::string line = "1 2 3 4 5 6 7 8 9 10";
std::smatch m;
std::vector<std::string> catchit;
while (regex_search(line, m, rx))
{
std::cout << "Pattern found " << m[i] << '\n';
catchit.push_back(m[i]);
line = m.suffix().str();
i++;
}
return 0;
}
This solves my problem without having to use regex, thank you very much #Nick
Why not std::cin? Or wrap your output from getline in a
std::stringstream and use operator>> to read numbers one at a time and
validate them then? E.g. std::stringstream stream(line); /* loop */
stream >> val; if (val < 0 || val > 11)...

std::cin with more complex objects

I have a text file which first describes some lines and then describes some colorful lines:
1 2 3 4
5 6 7 8
9 10 11 12
red 1 0 0 1 2 3 4
green 0 1 0 5 6 7 8
blue 0 0 1 9 10 11 12
The number of lines in each section is unknown at time of execution
I overloaded the std::cin >> operator for these structs:
struct Point { int x, y; }
struct Line { Point a, b; }
struct Color { float r, g, b; std::string name; };
struct ColorfulLine { Line line; Color color; };
(Full example here: http://ideone.com/bMOaL1 [already works - edited according to the accepted answer])
Now I need to iterate over the file using Lines and ColorfulLines:
Line line;
while(cin >> line) { cout << "We've got a line!\n"; }
ColorfulLine color_line;
while(cin >> color_line) { cout << "We've got a colorful line!\n"; }
// actually I'm putting them into std::lists but I skipped this part for simplicity
And here is the problem - the colorful lines are never fetched, i.e. the second loop is not executed.
I have an assumption why it happens but don't know how to fix it:
When std::cin tries to fetch the 4th Line, it fails because instead of a number there's the string "red".
Next, in the second while loop, std::cin tries to read a string (Color.name) but it sees a number, and then fails too.
I tried to put some random word before the ColorfulLines section hoping that when the first loop fails, the second will start reading from the "red" string, but it didn't.
How to fix this?
After the first loop breaks, std::cin is in a bad state. That's why the loop breaks in the first place. Performing reads on a bad stream fails immediately, thus the second loop is never entered.
To solve this, reset the error state after the first loop breaks with
std::cin.clear();

Reading numbers and strings from a file in C++

I know this question has been asked a lot, and I have gone through the most popular answer on stackoverflow.
I have a bunch of numbers in the following format:
4 // number of testcases
1 2 3 4 5 6 // Each line contains numbers for that particular testcase
1 4 5 6 7 8 9 19
12 3 5
1 4 9
The first line is the number of testcases. Each line following that contains numbers for that particular testcase.
I want to read line by line, process the numbers, output the solution and only then move to read to the second line.
In another stackoverflow question, the suggested solution is leading to a lot of duplication of data in the vector all_integers.
std::string line;
std::vector< std::vector<int> > all_integers;
while ( getline( std::cin, line ) ) {
std::istringstream is( line );
all_integers.push_back(
std::vector<int>( std::istream_iterator<int>(is),
std::istream_iterator<int>() ) );
for(auto it = all_integers.begin();it!=all_integers.end();it++) {
for(auto j = it->begin();j!=it->end();j++) {
cout << *j << " " ;
}
cout << endl;
}
What is the correct way of reading this from a file?
Follow up question:
In another file, I have input in the following format:
5 2
abc
bcd
eee
zyc
abv
abc bcd
zyc anv
The first line contains two numbers: m,n.
m : Number of words in the dictionary
n: Number of queries.
Then m number of words follow and last n lines read the number of queries that are to be made to it.
How can I read this efficiently? Is there any way to read the last K lines of a file efficiently in C++?

Ignoring the blank spaces at the end of a file

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);

Grabbing data from file using getline

So I have a file that has multiple columns of data like this:
1 2 3
4 5 6
7 8 9
etc...
And I'm traversing through this file with a while loop trying to store the data in a vector as I go along. But when I use a delimiter to deal with the spaces in between the data it only reads the first line and stops. The code for the while loop is as follows:
while(getline(infile,content, ' '))
{
double temp = atof(content.c_str();
cout << "value storing is: " << temp << endl;
data.push_back(temp);
}
Using the data above with this code I just get "1 2 3" as the output. So i'm not sure where I'm going wrong with this.
The column the numbers are in are also important when I crunch the data later. For example, every iteration of the while loop will add a counter and every time it goes to a new line will be another counter so with that i can figure out how many lines I have so when I need to compute something I can use i%(columnNumber) to grab that value.
Thanks for any light anyone can shed on my situation.
It's because there are no spaces after a new line.
This is what the file looks like (to std::getline())
1 space 2 space 3 newline 4 space 5 space 6 newline 7 space 8 space 9
I can't reproduce "1 2 3" as output. When I run your code, I get
value storing is: 1
value storing is: 2
value storing is: 3
value storing is: 5
value storing is: 6
value storing is: 8
value storing is: 9
where my test file looks like this:
1 2 3
4 5 6
7 8 9
To fix the problem, try doing something like this:
int main()
{
std::ifstream in("test");
std::string content;
std::vector<int> data;
while (getline(in, content))
{
std::stringstream linestream(content);
int value;
// Read an integer at a time from the line
while(linestream >> value)
{
// Add the integers from a line to a 1D array (vector)
data.push_back(value);
std::cout << "value storing is: " << value << std::endl;
}
}
}