CSV parser in C++ doesn't read the first element - c++

I extracted this piece of code to parse a CSV file, however it doesn't read the first element for the first n-1 rows. I can't figure it out why, and when I copy the data into a new empty file and save it as CSV file, the error disappears and it works fine. Here are the links for the original (error happens) and the copied (error doesn't happen) CSV file. Could you please help me as why this is happening?
Thank you.
#include <boost/tokenizer.hpp>
#include <fstream>
#include <string>
#include <vector>
#include <iostream>
#include <cstdlib>
int main(int argc, char** argv)
{
using namespace std;
if (argc != 2)
{
cerr << "Usage: " << argv[0] << " <csv file>" << endl;
return -1;
}
vector< vector<string> > csv_values;
fstream file(argv[1], ios::in);
if (file)
{
typedef boost::tokenizer< boost::char_separator<char> > Tokenizer;
boost::char_separator<char> sep(",");
string line;
while (getline(file, line))
{
Tokenizer info(line, sep); // tokenize the line of data
vector<string> values;
for (Tokenizer::iterator it = info.begin(); it != info.end(); ++it)
{
// convert data into double value, and store
values.push_back(it->c_str());
}
// store array of values
csv_values.push_back(values);
}
}
else
{
cerr << "Error: Unable to open file " << argv[1] << endl;
return -1;
}
// display results
cout.precision(1);
cout.setf(ios::fixed,ios::floatfield);
for (vector< vector<string> >::const_iterator it = csv_values.begin(); it != csv_values.end(); ++it)
{
const vector<string>& values = *it;
for (vector<string>::const_iterator it2 = values.begin(); it2 != values.end(); ++it2)
{
cout << *it2 << " ";
}
cout << endl;
}
}

New lines in your orginal file ends with a carriage return, which is read by your code with last varible in the line, and then printed. So first line is printed like this
1 2 3 4 5\r
and then you print space, which is printed at the beginning of the line, covering "1".
You could easily see that in debugger :)

Related

How to get int from a line of a text and add them together in c++?

Hi I have got an text file and inside writing:
15 7 152 3078
178 352 1 57
What I want to do is get the int's from first line, sum up the numbers and make it an integer. And than do it for the second line with another int. How can I do that with c++? Thanks for your help.
You can use stringstream to convert a string into integer. And to sum a vector of integer, use accumulate algorithm. You can pass a filename as first argument to the program, by default the program assume the filename as input.txt.
Here is a complete program to demonstrate this.
#include <iostream>
#include <fstream>
#include <sstream>
#include <numeric> // for accumulate
#include <vector>
int main(int argc, char *argv[]) {
std::string filename{"input.txt"};
if(argc > 1) {
filename = argv[1];
}
// open the input file
std::ifstream inputFile(filename);
if(!inputFile.is_open()) {
std::cerr << "Unable to open " << filename << std::endl;
return 1;
}
std::string line;
// read the file line by line
while(getline(inputFile, line)) {
if(line.empty()) continue;
std::stringstream ss(line);
std::vector<int> v;
int x;
// extract the content as integer from line
while(ss >> x) {
v.push_back(x);
}
// add them all
auto total = std::accumulate(v.begin(), v.end(), 0);
std::cout << total << std::endl;
}
}
As in Aamir's answer, but with separate listing of sums and numbers per line. Maybe that helps too.
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
int main(int argc, char *argv[]) {
std::string filename{"input.txt"};
if(argc > 1) {
filename = argv[1];
}
// open the input file
std::ifstream inputFile(filename);
if(!inputFile.is_open()) {
std::cerr << "Unable to open " << filename << std::endl;
return 1;
}
std::vector<int> v_numberSum;
std::vector<int> v_numbersPerLine;
std::string line;
// read the file line by line
int i = 0;
while(getline(inputFile, line)) {
if(line.empty()) continue;
v_numberSum.push_back(0);
v_numbersPerLine.push_back(0);
std::stringstream f(line);
std::string s;
int cnt = 0;
while (getline(f, s, ' ')) {
v_numberSum[i] += std::stoi(s);
cnt++;
}
v_numbersPerLine[i] = cnt;
i++;
}
int j = 0;
for (auto intItem: v_numberSum){
std::cout << "sum"<<j<<": " << intItem << " numbers per line: " << v_numbersPerLine[j] << std::endl;
j++;
}
}

How to remove an item of Vectors c++

i have this code and i want to find a word in my vector and delete the item that includes that word but, my code will delete from the first line until the item that i want, how can i fix that?
std::string s;
std::vector<std::string> lines;
while (std::getline(theFile, s))
{
lines.push_back(s);
}
//finding item in vector and changing it
for (unsigned i = 0; i < lines.size(); i++)
{
std::size_t found = lines[i].find(name);
if (found != std::string::npos)
{
lines.erase(lines.begin() + i);
}
}
Update 1:
this is my full Code:
I'm opening a file that contains some elements in this format
( David, 2002 , 1041 , 1957 )
( cleve, 2003 , 1071 , 1517 )
( Ali, 2005 , 1021 , 1937 )
i'm getting a user input and finding the line that contains it. then i want to remove that line completely so i import it to a vector and then i can't modify it
#include <iostream>
#include <string>
#include <vector>
#include <stream>
#include <algorithm>
using namespace std;
using std::vector;
int main(){
string srch;
string line;
fstream Myfile;
string name;
int counter;
Myfile.open("Patientlist.txt", ios::in | ios::out);
cout <<"Deleting your Account";
cout << "\nEnter your ID: ";
cin.ignore();
getline(cin, srch);
if (Myfile.is_open())
{
while (getline(Myfile, line))
{
if (line.find(srch) != string::npos)
{
cout << "\nYour details are: \n"
<< line << endl;
}
break;
}
}
else
{
cout << "\nSearch Failed... Patient not found!" << endl;
}
Myfile.close();
ifstream theFile("Patientlist.txt");
//using vectors to store value of file
std::string s;
std::vector<std::string> lines;
while (std::getline(theFile, s))
{
lines.push_back(s);
}
//finding item in vector and changing it
for (unsigned i = 0; i < lines.size(); i++)
{
std::size_t found = lines[i].find(name);
if (found != std::string::npos)
{
lines.erase(lines.begin() + i);
}
}
//writing new vector on file
ofstream file;
file.open("Patientlist.txt");
for (int i = 0; i < lines.size(); ++i)
{
file << lines[i] << endl;
}
file.close();
cout << "Done!";
}
The erasing loop is broken. The proper way is to use iterators and use the iterator returned by erase. Like so:
// finding item in vector and changing it
for (auto it = lines.begin(); it != lines.end();) {
if (it->find(name) != std::string::npos) {
it = lines.erase(it);
} else {
++it;
}
}
Or using the erase–remove idiom:
lines.erase(std::remove_if(lines.begin(), lines.end(),
[&name](const std::string& line) {
return line.find(name) != std::string::npos;
}), lines.end());
Or since C++20 std::erase_if(std::vector):
std::erase_if(lines, [&name](const std::string& line) {
return line.find(name) != std::string::npos;
});
You can use remove_if for this. The predicate argument should check if you can find a word in a line. Then remember to use erase to "shrink" the vector to its new size.
[Demo]
#include <algorithm> // remove_if
#include <iostream> // cout
#include <string>
#include <vector>
int main()
{
std::vector<std::string> lines{"one two three", "three four five", "five six one"};
lines.erase(
std::remove_if(std::begin(lines), std::end(lines), [](auto& line) {
return line.find("one") != std::string::npos;}),
std::end(lines)
);
for (auto& line : lines) { std::cout << line << "\n"; }
}

Why does getline() cut off CSV Input?

I'm trying to read and parse my CSV files in C++ and ran into an error.
The CSV has 1-1000 rows and always 8 columns.
Generally what i would like to do is read the csv and output only lines that match a filter criteria. For example column 2 is timestamp and only in a specific time range.
My problem is that my program cuts off some lines.
At the point where the data is in the string record variable its not cutoff. As soon as I push it into the map of int/vector its cutoff. Am I doing something wrong here?
Could someone help me identify what the problem truly is or maybe even give me a better way to do this?
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <map>
#include "csv.h"
using std::cout; using std::cerr;
using std::endl; using std::string;
using std::ifstream; using std::ostringstream;
using std::istringstream;
string readFileIntoString(const string& path) {
auto ss = ostringstream{};
ifstream input_file(path);
if (!input_file.is_open()) {
cerr << "Could not open the file - '"
<< path << "'" << endl;
exit(EXIT_FAILURE);
}
ss << input_file.rdbuf();
return ss.str();
}
int main()
{
int filterID = 3;
int filterIDIndex = filterID;
string filter = "System";
/*Filter ID's:
0 Record ID
1 TimeStamp
2 UTC
3 UserID
4 ObjectID
5 Description
6 Comment
7 Checksum
*/
string filename("C:/Storage Card SD/Audit.csv");
string file_contents;
std::map<int, std::vector<string>> csv_contents;
char delimiter = ',';
file_contents = readFileIntoString(filename);
istringstream sstream(file_contents);
std::vector<string> items;
string record;
int counter = 0;
while (std::getline(sstream, record)) {
istringstream line(record);
while (std::getline(line, record, delimiter)) {
items.push_back(record);
cout << record << endl;
}
csv_contents[counter] = items;
//cout << csv_contents[counter][0] << endl;
items.clear();
counter += 1;
}
I can't see a reason why you data is being cropped, but I have refactored you code slightly and using this it might be easier for you to debug the problem, if it doesn't just disappear on its own.
int main()
{
string path("D:/Audit.csv");
ifstream input_file(path);
if (!input_file.is_open())
{
cerr << "Could not open the file - '" << path << "'" << endl;
exit(EXIT_FAILURE);
}
std::map<int, std::vector<string>> csv_contents;
std::vector<string> items;
string record;
char delimiter = ';';
int counter = 0;
while (std::getline(input_file, record))
{
istringstream line(record);
while (std::getline(line, record, delimiter))
{
items.push_back(record);
cout << record << endl;
}
csv_contents[counter] = items;
items.clear();
++counter;
}
return counter;
}
I have tried your code and (after fixing the delimiter) had no problems, but I only had three lines of data, so if it is a memory issue it would have been unlikely to show.

Read and print a csv file with more than 2 column in c++ using multimap

I'm a beginner in c++ and required to write a c++ program to read and print a csv file like this.
DateTime,value1,value2
12/07/16 13:00,3.60,50000
14/07/16 20:00,4.55,3000
May I know how can I proceed with the programming?
I manage to get the date only via a simple multimap code.
I spent some time to make almost (read notice at the end) exact solution for you.
I assume that your program is a console application that receives the original csv-file name as a command line argument.
So see the following code and make required changes if you like:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <string>
std::vector<std::string> getLineFromCSV(std::istream& str, std::map<int, int>& widthMap)
{
std::vector<std::string> result;
std::string line;
std::getline(str, line);
std::stringstream lineStream(line);
std::string cell;
int cellCnt = 0;
while (std::getline(lineStream, cell, ','))
{
result.push_back(cell);
int width = cell.length();
if (width > widthMap[cellCnt])
widthMap[cellCnt] = width;
cellCnt++;
}
return result;
}
int main(int argc, char * argv[])
{
std::vector<std::vector<std::string>> result; // table with data
std::map<int, int> columnWidths; // map to store maximum length (value) of a string in the column (key)
std::ifstream inpfile;
// check file name in the argv[1]
if (argc > 1)
{
inpfile.open(argv[1]);
if (!inpfile.is_open())
{
std::cout << "File " << argv[1] << " cannot be read!" << std::endl;
return 1;
}
}
else
{
std::cout << "Run progran as: " << argv[0] << " input_file.csv" << std::endl;
return 2;
}
// read from file stream line by line
while (inpfile.good())
{
result.push_back(getLineFromCSV(inpfile, columnWidths));
}
// close the file
inpfile.close();
// output the results
std::cout << "Content of the file:" << std::endl;
for (std::vector<std::vector<std::string>>::iterator i = result.begin(); i != result.end(); i++)
{
int rawLen = i->size();
for (int j = 0; j < rawLen; j++)
{
std::cout.width(columnWidths[j]);
std::cout << (*i)[j] << " | ";
}
std::cout << std::endl;
}
return 0;
}
NOTE: Your task is just to replace a vector of vectors (type std::vector<std::vector<std::string>> that are used for result) to a multimap (I hope you understand what should be a key in your solution)
Of course, there are lots of possible solutions for that task (if you open this question and look through the answers you will understand this).
First of all, I propose to consider the following example and to try make your task in the simplest way:
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
int main()
{
string str = "12/07/16 13:00,3.60,50000";
stringstream ss(str);
vector<string> singleRow;
char ch;
string s = "";
while (ss >> ch)
{
s += ch;
if (ss.peek() == ',' || ss.peek() == EOF )
{
ss.ignore();
singleRow.push_back(s);
s.clear();
}
}
for (vector<string>::iterator i = singleRow.begin(); i != singleRow.end(); i++)
cout << *i << endl;
return 0;
}
I think it can be useful for you.

print out the last 10 lines of a file

I want to have the option to print out the last 10 lines of a textfile . with this program I've been able to read the whole textfile, but I can't figure out how to manipulate the array in which the textfile is saved, any help?
// Textfile output
#include<fstream>
#include<iostream>
#include<iomanip>
using namespace std;
int main() {
int i=1;
char zeile[250], file[50];
cout << "filename:" << flush;
cin.get(file,50); ///// (1)
ifstream eingabe(datei , ios::in); /////(2)
if (eingabe.good() ) { /////(3)
eingabe.seekg(0L,ios::end); ////(4)
cout << "file:"<< file << "\t"
<< eingabe.tellg() << " Bytes" ////(5)
<< endl;
for (int j=0; j<80;j++)
cout << "_";
cout << endl;
eingabe.seekg(0L, ios::beg); ////(6)
while (!eingabe.eof() ){ ///(7)
eingabe.getline(zeile,250); ///(8)
cout << setw(2) << i++
<< ":" << zeile << endl;
}
}
else
cout <<"dateifehler oder Datei nicht gefunden!"
<< endl;
return 0;
}
Try this:
#include <list>
#include <string>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
// A class that knows how to read a line using operator >>
struct Line
{
std::string theLine;
operator std::string const& () const { return theLine; }
friend std::istream& operator>>(std::istream& stream, Line& l)
{
return std::getline(stream, l.theLine);
}
};
// A circular buffer that only saves the last n lines.
class Buffer
{
public:
Buffer(size_t lc)
: lineCount(lc)
{}
void push_back(std::string const& line)
{
buffer.insert(buffer.end(),line);
if (buffer.size() > lineCount)
{
buffer.erase(buffer.begin());
}
}
typedef std::list<std::string> Cont;
typedef Cont::const_iterator const_iterator;
typedef Cont::const_reference const_reference;
const_iterator begin() const { return buffer.begin(); }
const_iterator end() const { return buffer.end();}
private:
size_t lineCount;
std::list<std::string> buffer;
};
// Main
int main()
{
std::ifstream file("Plop");
Buffer buffer(10);
// Copy the file into the special buffer.
std::copy(std::istream_iterator<Line>(file), std::istream_iterator<Line>(),
std::back_inserter(buffer));
// Copy the buffer (which only has the last 10 lines)
// to std::cout
std::copy(buffer.begin(), buffer.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
Basically, you are not saving the file contents to any array. The following sample will give you a head start:
#include <iostream>
#include <vector>
#include <string>
int main ( int, char ** )
{
// Ask user for path to file.
std::string path;
std::cout << "filename:";
std::getline(std::cin, path);
// Open selected file.
std::ifstream file(path.c_str());
if ( !file.is_open() )
{
std::cerr << "Failed to open '" << path << "'." << std::endl;
return EXIT_FAILURE;
}
// Read lines (note: stores all of it in memory, might not be your best option).
std::vector<std::string> lines;
for ( std::string line; std::getline(file,line); )
{
lines.push_back(line);
}
// Print out (up to) last ten lines.
for ( std::size_t i = std::min(lines.size(), std::size_t(10)); i < lines.size(); ++i )
{
std::cout << lines[i] << std::endl;
}
}
It would probably be wiser to avoid storing the whole file into memory, so you could re-write the last 2 segments this way:
// Read up to 10 lines, accumulating.
std::deque<std::string> lines;
for ( std::string line; lines.size() < 0 && getline(file,line); )
{
lines.push_back(line);
}
// Read the rest of the file, adding one, dumping one.
for ( std::string line; getline(file,line); )
{
lines.pop_front();
lines.push_back(line);
}
// Print out whatever is left (up to 10 lines).
for ( std::size_t i = 0; i < lines.size(); ++i )
{
std::cout << lines[i] << std::endl;
}
The eof() function does not do what you and it seems a million other C++ newbies think it does. It does NOT predict if the next read will work. In C++ as in any other language, you must check the status of each read operation, not the state of the input stream before the read. so the canonical C++ read line loop is:
while ( eingabe.getline(zeile,250) ) {
// do something with zeile
}
Also, you should be reading into a std::string, and get rid of that 250 value.
Do a circular buffer with 10 slots and while reading the file lines, putting them into this buffer. When you finish thr file, do a position++ to go to the first element and print them all.
Pay attention for null values if the file has less than 10 lines.
Have an array of strings with size 10.
Read the first line and store into the array
Continue reading till the array is full
Once the array is full delete the first entry so that you can enter new line
Repeate step 3 and 4 till the file is finished reading.
I investigate proposed approaches here and describe all in my blog post. There is a better solution but you have to jump to the end and persist all needed lines:
std::ifstream hndl(filename, std::ios::in | std::ios::ate);
// and use handler in function which iterate backward
void print_last_lines_using_circular_buffer(std::ifstream& stream, int lines)
{
circular_buffer<std::string> buffer(lines);
std::copy(std::istream_iterator<line>(stream),
std::istream_iterator<line>(),
std::back_inserter(buffer));
std::copy(buffer.begin(), buffer.end(),
std::ostream_iterator<std::string>(std::cout));
}