C++ Read from file and assign to a variables - c++

i have a question.
I have a file in format like this:
A B
C D
E F
X Y
X2 Y2
X3 Y3
I know how to assign A,B,C,D,E,F,X,Y (each file i check have this data) but sometimes i have more data like X2 Y2, X3, Y3 and i want to assing these also (without previous knowledge about how many of these are in the file).
Actually my code looks like this:
reading >> a >> b >> c >> d >> e >> f >> x >> y;
Could You help me? Thank You

This solution with vectors might solve the problem:
#include <vector>
#include <string>
#include <iterator>
#include <iostream>
#include <fstream>
using namespace std;
void getItems(vector<string>& v, string path)
{
ifstream is(path.c_str());
istream_iterator<string> start(is), end;
vector<string> items(start, end);
v = items;
}
int main()
{
vector<string> v;
getItems(v, "C:\test.txt");
vector<string>::iterator it;
for (it = v.begin(); it != v.end(); it++)
cout << *it << endl;
return 0;
}
Note: here i am assuming that your file is in C:\test.txt

You can input all of them as a string. Give the header as #input and use gets() function to input the entire input. Then work on the string. You can differentiate between the numbers by neglecting space(" ") and new lines ("\n").
Hope this helps!

You can use 2D vector:
Input:
1 2 3
4 5
6
7 8 9
Code:
int val;
string line;
ifstream myfile ("example.txt");
vector<vector<int> > LIST;
if (myfile.is_open())
{
while ( getline(myfile,line) )
{
vector<int> v;
istringstream IS(line);
while( IS >> val)
{
v.push_back(val);
}
LIST.push_back(v);
}
myfile.close();
}
for(int i=0; i<LIST.size(); i++)
{
for(int j=0; j<LIST[i].size(); j++)
{
cout << LIST[i][j] << " ";
}
cout << endl;
}
Output:
1 2 3
4 5
6
7 8 9

In the case where you don't know how much data is in the file, it is worth to use a
WHILE loop with the condition that you perform the while loop until it reaches the end of the file.
Something like this (ensure you include: iostream, fstream, and string):
int main () {
string line;
ifstream thefile ("test.txt");
if (thefile.is_open())
{
while (thefile.good() )
{
getline (thefile, line);
}
thefile.close();
}
else
{
cout << "Unable to open\n";
}
return 0;
}

If I understood you well you want to be sure that all lines in the file must be read.
With the following code I solved the problem for me:
std::ifstream file_reading( filename_path_.c_str(), std::ios::in );
if( file_reading ) {
std::string buffer;
unsigned int line_counter = 0;
while( std::getline( file_reading, buffer ) ) {
std::istringstream istr;
istr.str( buffer );
if( buffer.empty() )
break;
istr >> x_array[local_counter] >> y_array[local_counter];
line_counter++;
}
}
using getline and a while loop you all get all lines in the file and store them in a std::vector which is resizable.
The instruction break will quit if no more data are found in the next line.

Related

How to read a CSV dataset in which each row has a distinct length. C++

I'm just new to C++ and am studying how to read data from csv file.
I want to read the following csv data into vector. Each row is a vector. The file name is path.csv:
0
0 1
0 2 4
0 3 6 7
I use the following function:
vector<vector<int>> read_multi_int(string path) {
vector<vector<int>> user_vec;
ifstream fp(path);
string line;
getline(fp, line);
while (getline(fp, line)) {
vector<int> data_line;
string number;
istringstream readstr(line);
while (getline(readstr, number, ',')) {
//getline(readstr, number, ',');
data_line.push_back(atoi(number.c_str()));
}
user_vec.push_back(data_line);
}
return user_vec;
}
vector<vector<int>> path = read_multi_int("C:/Users/data/paths.csv");
Print funtion:
template <typename T>
void print_multi(T u)
{
for (int i = 0; i < u.size(); ++i) {
if (u[i].size() > 1) {
for (int j = 0; j < u[i].size(); ++j) {
//printf("%d ", u[i][j]);
cout << u[i][j] << " ";
}
printf("\n");
}
}
printf("\n");
}
Then I get
0 0 0
0 1 0
0 2 4
0 3 6 7
Zeros are added at the end of the rows. Is possible to just read the data from the csv file without adding those extra zeros? Thanks!
Based on the output you are seeing and the code with ',' commas, I beleive that your actual input data really looks like this:
A,B,C,D
0,,,
0,1,,
0,2,4,
0,3,6,7
So the main change is to replace atoi with strtol, as atoi will always return 0 on a failure to parse a number, but with strtol we can check if the parse succeeded.
That means that the solution is as follows:
vector<vector<int>> read_multi_int(string path) {
vector<vector<int>> user_vec;
ifstream fp(path);
string line;
getline(fp, line);
while (getline(fp, line)) {
vector<int> data_line;
string number;
istringstream readstr(line);
while (getline(readstr, number, ',')) {
char* temp;
char numberA[30];
int numberI = strtol(number.c_str(), &temp, 10);
if (temp == number || *temp != '\0' ||
((numberI == LONG_MIN || numberI == LONG_MAX) && errno == ERANGE))
{
// Could not convert
}else{
data_line.emplace_back(numberI);
}
}
user_vec.emplace_back(data_line);
}
return user_vec;
}
Then to display your results:
vector<vector<int>> path = read_multi_int("C:/Users/data/paths.csv");
for (const auto& row : path)
{
for (const auto& s : row) std::cout << s << ' ';
std::cout << std::endl;
}
Give the expected output:
0
0 1
0 2 4
0 3 6 7
Already very good, but there is one obvious error and another error in your print function. Please see, how I output the values, with simple range based for loops.
If your source file does not contain a comma (','), but a different delimiter, then you need to call std::getline with this different delimiter, in your case a blank (' '). Please read here about std::getline.
If we then use the following input
Header
0
0 1
0 2 4
0 3 6 7
with the corrected program.
#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
vector<vector<int>> read_multi_int(string path) {
vector<vector<int>> user_vec;
ifstream fp(path);
string line;
getline(fp, line);
while (getline(fp, line)) {
vector<int> data_line;
string number;
istringstream readstr(line);
while (getline(readstr, number, ' ')) {
//getline(readstr, number, ',');
data_line.push_back(atoi(number.c_str()));
}
user_vec.push_back(data_line);
}
return user_vec;
}
int main() {
vector<vector<int>> path = read_multi_int("C:/Users/data/paths.csv");
for (vector<int>& v : path) {
for (int i : v) std::cout << i << ' ';
std::cout << '\n';
}
}
then we receive this as output:
0
0 1
0 2 4
0 3 6 7
Which is correct, but unfortunately different from your shown output.
So, your output routine, or some other code, may also have some problem.
Besides. If there is no comma, then you can take advantage of formatted input functions using the extraction operator >>. This will read your input until the next space and convert it automatically to a number.
Additionally, it is strongly recommended, to initialize all variables during definition. You should do this always.
Modifying your code to use formatted input, initialization, and, maybe, better variable names, then it could look like the below.
#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
vector<vector<int>> multipleLinesWithIntegers(const string& path) {
// Here we will store the resulting 2d vector
vector<vector<int>> result{};
// Open the file
ifstream fp{ path };
// Read header line
string line{};
getline(fp, line);
// Now read all lines with numbers in the file
while (getline(fp, line)) {
// Here we will store all numbers of one line
vector<int> numbers{};
// Put the line into an istringstream for easier extraction
istringstream sline{ line };
int number{};
while (sline >> number) {
numbers.push_back(number);
}
result.push_back(numbers);
}
return result;
}
int main() {
vector<vector<int>> values = multipleLinesWithIntegers("C:/Users/data/paths.csv");
for (const vector<int>& v : values) {
for (const int i : v) std::cout << i << ' ';
std::cout << '\n';
}
}
And, the next step would be to use a some more advanced style:
#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <iterator>
auto multipleLinesWithIntegers(const std::string& path) {
// Here we will store the resulting 2d vector
std::vector<std::vector<int>> result{};
// Open the file and check, if it could be opened
if (std::ifstream fp{ path }; fp) {
// Read header line
if (std::string line{}; getline(fp, line)) {
// Now read all lines with numbers in the file
while (getline(fp, line)) {
// Put the line into an istringstream for easier extraction
std::istringstream sline{ line };
// Get the numbers and add them to the result
result.emplace_back(std::vector(std::istream_iterator<int>(sline), {}));
}
}
else std::cerr << "\n\nError: Could not read header line '" << line << "'\n\n";
}
else std::cerr << "\n\nError: Could not open file '" << path << "'\n\n'";
return result;
}
int main() {
const std::vector<std::vector<int>> values{ multipleLinesWithIntegers("C:/Users/data/paths.csv") };
for (const std::vector<int>& v : values) {
for (const int i : v) std::cout << i << ' ';
std::cout << '\n';
}
}
Edit
You have shown your output routine. That should be changed to:
void printMulti(const std::vector<std::vector<int>>& u)
{
for (int i = 0; i < u.size(); ++i) {
if (u[i].size() > 0) {
for (int j = 0; j < u[i].size(); ++j) {
std::cout << u[i][j] << ' ';
}
std::cout << '\n';
}
}
std::cout << '\n';
}

Parsing string in C++

Currently,
I have this string us,muscoy,Muscoy,CA,,34.1541667,-117.3433333.
I need to parse US and CA. I was able to parse US correctly by this:
std::string line;
std::ifstream myfile ("/Users/settingj/Documents/Country-State Parse/worldcitiespop.txt");
while( std::getline( myfile, line ) )
{
while ( myfile.good() )
{
getline (myfile,line);
//std::cout << line << std::endl;
std::cout << "Country:";
for (int i = 0; i < 2/*line.length()*/; i++)
{
std::cout << line[i];
}
}
}
But i'm having an issue parsing to CA.
Heres some code I dug up to find the amount of ',' occurrences in a string but I am having issues saying "parse this string between the 3rd and 4th ',' occurrence.
// Counts the number of ',' occurrences
size_t n = std::count(line.begin(), line.end(), ',');
std::cout << n << std::endl;
You can use boost::split function (or boost::tokenizer) for this purpose. It will split string into vector<string>.
std::string line;
std::vector<std::string> results;
boost::split(results, line, boost::is_any_of(","));
std::string state = results[3];
It's not for a class... Haha... it seems like a class question though...
I have the solution:
int count = 0;
for (int i = 0; i < line.length(); i++)
{
if (line[i] == ',')
count++;
if (count == 3){
std::cout << line[i+1];
if (line[i+1] == ',')
break;
}
}
Just had to think about it more :P
This is STL version, works pretty well for simple comma separated input files.
#include<fstream>
#include <string>
#include <iostream>
#include<vector>
#include<sstream>
std::vector<std::string> getValues(std::istream& str)
{
std::vector<std::string> result;
std::string line;
std::getline(str,line);
std::stringstream lineS(line);
std::string cell;
while(std::getline(lineS,cell,','))
result.push_back(cell);
return result;
}
int main()
{
std::ifstream f("input.txt");
std::string s;
//Create a vector or vector of strings for rows and columns
std::vector< std::vector<std::string> > v;
while(!f.eof())
v.push_back(getValues(f));
for (auto i:v)
{
for(auto j:i)
std::cout<<j<< " ";
std::cout<<std::endl;
}
}

C++ cin read STDIN

How to use C++ to get all the STDIN and parse it?
For example, my input is
2
1 4
3
5 6 7
I want to use C++ to read the STDIN using cin and store the each line in an array. So, it will be an vector/array of array of integers.
Thanks!
Since this isn't tagged as homework, here's a small example of reading from stdin using std::vectors and std::stringstreams. I added an extra part at the end also for iterating through the vectors and printing out the values. Give the console an EOF (ctrl + d for *nix, ctrl + z for Windows) to stop it from reading in input.
#include <iostream>
#include <vector>
#include <sstream>
int main(void)
{
std::vector< std::vector<int> > vecLines;
// read in every line of stdin
std::string line;
while ( getline(std::cin, line) )
{
int num;
std::vector<int> ints;
std::istringstream ss(line); // create a stringstream from the string
// extract all the numbers from that line
while (ss >> num)
ints.push_back(num);
// add the vector of ints to the vector of vectors
vecLines.push_back(ints);
}
std::cout << "\nValues:" << std::endl;
// print the vectors - iterate through the vector of vectors
for ( std::vector< std::vector<int> >::iterator it_vecs = vecLines.begin();
it_vecs != vecLines.end(); ++it_vecs )
{
// iterate through the vector of ints and print the ints
for ( std::vector<int>::iterator it_ints = (*it_vecs).begin();
it_ints < (*it_vecs).end(); ++it_ints )
{
std::cout << *it_ints << " ";
}
std::cout << std::endl; // new line after each vector has been printed
}
return 0;
}
Input/Output:
2
1 4
3
5 6 7
Values:
2
1 4
3
5 6 7
EDIT: Added a couple more comments to the code. Also note that an empty vectors of ints can be added to vecLines (from an empty line of input), that's intentional so that the output is the same as the input.
int main ()
{
char line[100];
while(!cin.eof()){
cin.getline(line, 100);
printf("%s\n", line);
}
return 0;
}
Sorry, I just wasn't sure if there's any way better than this.
This one should fit your requirement , use istringstream to separate the line into an array.
#include <iostream>
#include <vector>
#include <sstream>
#include <string>
using namespace std;
int main()
{
string s("A B C D E F G");
vector<string> vec;
istringstream iss(s);
do
{
string sub;
iss >> sub;
if ( ! sub.empty() )
vec.push_back (sub);
} while (iss);
vector<string>::iterator it = vec.begin();
while ( it != vec.end() )
{
cout << *it << endl;
it ++;
}
return 0;
}

Write CSV file into vectors in C (continued)

Basically I have 14800x8 matrix that has been extracted from matlab as CSV file ("moves.mo"). I need to read this file into 14800 vectors with 8 values each.
Here is a few lines from the file:
1,2,3,4,-1,-3,-2,-4
1,2,3,5,-1,-3,-2,-5
1,2,3,6,-1,-3,-2,-6
1,2,3,7,-1,-3,-2,-7
1,2,3,8,-1,-3,-2,-8
1,2,3,9,-1,-3,-2,-9
I wrote the following code:
#include <iostream>
#include <fstream>
#include<stdio.h>
#include <string>
#include <istream>
#include <vector>
#include <sstream>
using namespace std;
int main()
{
std::fstream inputfile;
inputfile.open("moves.da");
std::vector< std::vector<int> > vectorsmovesList; //declare vector list
while (inputfile) {
std::string s;
if (!getline( inputfile, s )) break;
istringstream ss( s );
vector <int> recordmove;
while (ss)
{
if (!getline( ss, s, ',' )) break;
int recordedMoveInt = atoi(s.c_str());
recordmove.push_back( recordedMoveInt );
}
vectorsmovesList.push_back( recordmove );
}
if (!inputfile.eof())
{
cerr << "Fooey!\n";
}
It compiles but does not give me desirable output (i.e. just prints Fooey!) . I don't know why... This problem at this point is driving me insane.
Please help!
There are better ways to read integers in C++. For example:
std::string s;
if (!getline( inputfile, s )) break;
istringstream ss( s );
int recordedMove;
while (ss >> recordedMove)
{
recordmove.push_back(recordedMove);
// consume the commas between integers. note if there are no
// separating commas, you will lose some integers here.
char garbage;
ss >> garbage;
}
Also, you're not printing out your result anywhere. Here's how you would do it:
vector<vector<int> >::const_iterator ii;
for (ii = vectorsmovesList.begin(); ii != vectorsmovesList.end(); ++ii)
{
vector<int>::const_iterator jj;
for (jj = ii->begin(); jj != ii->end(); ++jj)
cout << *jj << ' ';
cout << endl;
}
Obviously, you'd do that after you've parsed and closed the CSV file.

Detect newline byte from filestream

I'm trying to collect information from a textfile which contains names of organisations (without spaces) and floating integers. I want to store this information in an array structure.
The problem I'm having so far is collecting the information. Here is a sample of the textfile:
CBA 12.3 4.5 7.5 2.9 4.1
TLS 3.9 1 8.6 12.8 4.9
I can have up to 128 different numbers for each organisation, and up to 200 organisations in the textfile.
This is what my structure looks like so far:
struct callCentre
{
char name[256];
float data[20];
};
My main:
int main()
{
callCentre aCentre[10];
getdata(aCentre);
calcdata(aCentre);
printdata(aCentre);
return 0;
}
And the getdata function:
void getdata(callCentre aCentre[])
{
ifstream ins;
char dataset[20];
cout << "Enter the name of the data file: ";
cin >> dataset;
ins.open(dataset);
if(ins.good())
{
while(ins.good())
{
ins >> aCentre[c].name;
for(int i = 0; i < MAX; i++)
{
ins >> aCentre[c].data[i];
if(ins == '\n')
break;
}
c++;
}
}
else
{
cout << "Data files couldnt be found." << endl;
}
ins.close();
}
What I'm trying to achieve in my getdata function is this: store the organisation name first into the structure, then read each float into the data array until the program detects a newline byte. However, so far my check for the newline byte isn't working.
Assume that variables c and MAX are already defined.
How should I go about this properly?
The >> operator treats whitespace as a delimiter, and that includes newlines, so it just eats those and you never see them.
You need to read lines and then chop the lines up. The following bit of hackery illustrates the basic idea:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
string line;
while( getline( cin, line ) ) {
istringstream is( line );
string cs;
is >> cs;
double vals[10];
int i = 0;
while( is >> vals[i] ) {
i++;
}
cout << "CS: " << cs;
for ( int j = 0; j < i; j++ ) {
cout << " " << vals[j];
}
cout << endl;
}
}
char byte = ins.peek();
Or
if(ins.peek() == '\n') break;
(Edit): You'll want to also check for an eof after your peek(), because some files may not have a ending newline.
I'd like to point out that you might want to consider using a vector<callCentre> instead of a static array. If your input file length exceeds the capacity of the array, you'll walk all over the stack.
I would read the file, one line after another and parse each line individually for the values:
std::string line;
while (std::getline(ins, line)) {
std::istringstream sline(line);
sline >> aCentre[c].name;
int i = 0;
while (sline >> aCentre[c].data[i])
i++;
c++;
}