how to read line and change to integer numbers fstream - c++

I am new to programming and I have a data.txt file with the following content:
bumbumbow
1 0 3 9 8
bumbumbum
1 0 3 9 :0
I want to read the line 2: 1 0 3 9 8 and to turn it into integer numbers but I have an error.
What is the problem? Here is my code:
#include <iostream>
#include <fstream>
#include <limits>
#include<string>
#include<vector>
std::fstream& GotoLine(std::fstream& file, unsigned int num) {
file.seekg(std::ios::beg);
for (int i = 0; i < num - 1; ++i) {
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return file;
}
int main() {
int result, i = 0;
std::vector<int> Array;
using namespace std;
std::fstream file("data.txt");
GotoLine(file, 2);
std::string line2;
std::getline(file, line2);
for (int result; std::getline(file, line2); result = std::stoi(line2))
{
Array.push_back(result);
std::cout << "Read in the number: " << result << "\n\n";
}
return 0;
}
thanks in advance guys

The crash occures due to calling std::stoi() with a wrong parameter "1 0 3 9 8".
You need to replace std::getline(file, line2); result = std::stoi(line2) inside the for loop with something splitting line2 into tokens and calling std::stoi() for those tokens. You can see how to split, for example, here:
Right way to split an std::string into a vector<string>

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';
}

How can I read as string and then make it int vector;

Lets say I have txt.file as
7 8 9
10 11 1
14 15 1
I want to keep the line and then put them in a nested vector. I have done this:
#include <sstream>
#include <fstream>
using namespace std;
int main()
{
vector<vector<int> > data;
vector<int> temp;
string file;
cout << "Enter a file: ";
cin >> file;
ifstream infile(file);
if (!infile.good()) {
cout << "Enter a valid file: " << endl;
return 1;
}
string read;
while (!infile.eof()) {
getline(infile, read);
istringstream iss(read);
copy(istream_iterator<int>(iss), istream_iterator<int>(), back_inserter(temp));
data.push_back(temp);
}
for (int i = 0; i < data.size(); i++) {
for (int j = 0; j < data[i].size(); j++) {
cout << data[i][j] << " ";
}
cout << endl;
}
}
Now the output I get is like this:
7 8 9
7 8 9 10 11 1
7 8 9 10 11 1 14 15 1
I am not sure why previous content is repeating. Any help would be appreciated. Thank you!
Among the multitude of things wrong.
You use std::cin and std::cout, but never #include <iostream>
You use std::vector, but never #include <vector>
You use std::string, but never #include <string>
You append your populated line vector, but never reset the vector.
Note that you don't have to do (4) if you simply ensure the vector being appended from is, in fact, in local scope and as such expires before the next line. Better still, just use a temporary (which I'll demonstrate next).
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>
#include <iterator>
int main()
{
std::vector<std::vector<int>> data;
std::cout << "Enter a file: ";
std::cout.flush();
std::string filename;
if (std::cin >> filename)
{
std::ifstream file(filename);
if (file.is_open())
{
std::string line;
while (std::getline(file, line))
{
std::istringstream iss(line);
data.emplace_back(
std::istream_iterator<int>{iss},
std::istream_iterator<int>{});
}
}
}
for (auto const &v : data)
{
for (auto x : v)
std::cout << x << ' ';
std::cout.put('\n');
}
}
A notable problem fixed here is the avoidance of using std::istream::eof in a loop conditional. It is rarely correct, and in your case, it was wrong. See this question and answers for why: Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())) considered wrong?
back_inserter(temp) is adding your next lines to temp but you don't reset the variable so every line is appended to the end.

Comparing elements of text file between each other

I am trying to compare blocks of three numbers with each other to make a new output file with only the ones that meet that: first digit of the block is less than the second and less than the third, the second digit in the block has to be greater than the first but less than the third.
This is my code for the input file:
int main()
{
ofstream outfile ("test.txt");
outfile << "123 456 789 123 123 432 \n 123 243 " << endl;
I want to split this in blocks of three like"123", "456" and so on to be able to only write only the ones that meet the requirement in the new output file. I decided to conver the whole file into an integer vector to be able to compare them.
char digit;
ifstream file("test.txt");
vector<int> digits;
while(file >> digit) {
digits.push_back(digit - '0');
}
and I suppose that the method that compares them would look something like this:
bool IsValid(vector<int> digits){
for(int i=0; i<digits.size(); i++){
if(digits[0] < digits[1] & digits[0] < digits[2] & digits[1]<digits[2])
return true;
else{
return false;
}
}
}
However this would just compare the first block, would you do it differently? or should I keep doing the vector idea
You can do in this way. The "get" read a single char and when there are 3 digits the function IsValid is called.
#include <fstream>
#include <string>
#include <vector>
using namespace std;
bool IsValid(vector<int> digits)
{
if(digits[0] < digits[1] & digits[0] < digits[2] & digits[1]<digits[2])
return true;
else
return false;
}
int main()
{
ifstream in("test.txt");
ofstream out("output.txt");
char tmp;
vector<int> digits;
while(in.get(tmp))
{
if(tmp!=' ' and tmp!='\n')
{
digits.push_back(tmp-'0');
if(digits.size()==3)
{
if(IsValid(digits))
out<<digits[0]<<digits[1]<<digits[2]<<endl;
digits.clear();
}
}
}
out.close();
in.close();
}
if you task is : first digit of the block is less than the second and less than the third, the second digit in the block has to be greater than the first but less than the third - you num in string type - sorted - use it )) if data is 3 digits and space separeted )))
std::stringstream ss{line}; - for example like fstream )))
#include <iostream>
#include <vector>
#include <iterator>
#include <string>
#include <sstream>
#include <algorithm>
int main() {
std::string line{"123 456 789 123 123 432 123 243 "};
std::cout << line << std::endl;
std::string out_line;
std::stringstream ss{line};
std::string tmp_str;
while(ss >> tmp_str) {
if (std::is_sorted(std::begin(tmp_str), std::end(tmp_str))) {
out_line += tmp_str + " ";
}
}
std::cout << out_line << std::endl;
return 0;
}

How to read specific file fstream?

I have a data.txt file, and its contents are:
[exe1]
1 0 2 9 3 8
----------
[exe2]
----------
10 2 9 3 8:0
I want to read line 2: 1 0 2 9 3 8. But my output is only 1.
My code:
#include <iostream>
#include <fstream>
#include <limits>
#include<string>
std::fstream& GotoLine(std::fstream& file, unsigned int num) {
file.seekg(std::ios::beg);
for (int i = 0; i < num - 1; ++i) {
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return file;
}
int main() {
using namespace std;
fstream file("data.txt");
GotoLine(file, 2);
std::string line2;
file >> line2;
std::cout << line2;
cin.get();
return 0;
}
What is my problem? Sorry, I'm new in programming.
file >> line2; will stop reading a the first white space and hence reads only "1" because the extraction operator >> uses space as a deliminator.
you may want to use getline as getline(file,line2)
The input operator >> reads space delimited strings, if you want to read a whole line you need to use std::getline:
std::string line2;
std::getline(file, line);

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