The text file provided has an undetermined number of lines, each line containing 3 doubles separated by commas. For example:
-0.30895,0.35076,-0.88403
-0.38774,0.36936,-0.84453
-0.44076,0.34096,-0.83035
...
I want to read this data from the file line by line and then split it on the comma(,) sign and save it in an N by 3 array, let's call it Vertices [N] [3], where N designates the undefined number of lines in the file.
My code so far:
void display() {
string line;
ifstream myfile ("File.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
// I think the I should do 2 for loops here to fill the array as expected
}
myfile.close();
}
else cout << "Unable to open file";
}
The Problem: I managed to open the file and read line by line, but I have no idea how to pass the values into the requested array.
Thank you.
EDIT:
I have tried modifying my code according to the suggestions i received to the following:
void display() {
string line;
ifstream classFile ("File.txt");
vector<string> classData;
if (classFile.is_open())
{
std::string line;
while(std::getline(classFile, line)) {
std::istringstream s(line);
std::string field;
while (getline(s, field,',')) {
classData.push_back(line);
}
}
classFile.close();
}
else cout << "Unable to open file";
}
Is this the correct? and how can i access each field of the vector i created? (like in an array for example)?
I also noticed that these are of type string, how can i convert them to type float?
Thank you (:
There are many ways to approach this problem. Personally, I would implement a linked-list to save each line read out of the file in its own memory buffer. Once the entire file was read out, I would know how many lines were in the file and process each line in the list using strtok and strtod to convert the values.
Here's some pseudo code to get you rolling:
// Read the lines from the file and store them in a list
while ( getline (myfile,line) )
{
ListObj.Add( line );
}
// Allocate memory for your two-dimensional array
float **Vertices = (float **)malloc( ListObj.Count() * 3 * sizeof(float) );
// Read each line from the list, convert its values to floats
// and store the values in your array
int i = j = 0;
while ( line = ListObj.Remove() )
{
sVal = strtok( line, ",\r\n" );
fVal = (float)strtod( sVal, &pStop );
Verticies[i][j++] = fVal;
sVal = strtok( sVal + strlen(sVal) + 1, ",\r\n" );
fVal = (float)strtod( sVal, &pStop );
Verticies[i][j++] = fVal;
sVal = strtok( sVal + strlen(sVal) + 1, ",\r\n" );
fVal = (float)strtod( sVal, &pStop );
Verticies[i][j] = fVal;
i++;
j = 0;
}
The code after edit is right.You can access a vector value in c++ just like you access the values in a normal c++ array.Like classdata[i]You can find more here . Vector reference
And as for your question about converting string to float.In c++ you can directly do this by using stof ie stof(-0.883) you can find reference again here string to float
Best of luck and hope this helps :)
Related
I have a txt file with a lot of things in it.
The lines have this pattern: 6 spaces then 1 int, 1 space, then a string.
Also, the 1st line has the amount of lines that the txt has.
I want to put the integers in an array of ints and the string on an array of strings.
I can read it and put it into an array , but only if I'm considering the ints as chars and putting into one array of strings.When I try to separate things I have no idea on how I'd do it. Any ideas?
The code I used for putting everything in an array was this:
int size()
{
ifstream sizeX;
int x;
sizeX.open("cities.txt");
sizeX>>x;
return x;
};
int main(void)
{
int size = size();
string words[size];
ifstream file("cities.txt");
file.ignore(100000,'\n');
if(file.is_open())
{
for(int i=0; i<size; i++)
{
getline(file,words[i]);
}
}
}
Just to start I'm going to provide some tips about your code:
int size = size();
Why do you need to open the file, read the first line and then close it? That process can be done opening the file just once.
The code string words[size]; is absolutely not legal C++. You cannot instantiate a variable-length-array in C++. That C feature has been not included in C++ standard (some ref). I suggest you to replace with std::vector, which is more C++ code.
Here I write a snippet of function which perform what you need.
int parse_file(const std::string& filename,
std::vector<std::string>* out_strings,
std::vector<int>* out_integers) {
assert(out_strings != nullptr);
assert(out_integers != nullptr);
std::ifstream file;
file.open(filename, std::ios_base::in);
if (file.fail()) {
// handle the error
return -1;
}
// Local variables
int num_rows;
std::string line;
// parse the first line
std::getline(file, line);
if (line.size() == 0) {
// file empty, handle the error
return -1;
}
num_rows = std::stoi(line);
// reserve memory
out_strings->clear();
out_strings->reserve(num_rows);
out_integers->clear();
out_integers->reserve(num_rows);
for (int row = 0; row < num_rows; ++row) {
// read the line
std::getline(file, line);
if (line.size() == 0) {
// unexpected end of line, handle it
return -1;
}
// get the integer
out_integers->push_back(
std::stoi(line.substr(6, line.find(' ', 6) - 6)));
// get the string
out_strings->push_back(
line.substr(line.find(' ', 6) + 1, std::string::npos));
}
file.close();
return 0;
}
You can definitely improved it, but I think it's a good point where to start.
The last suggest I can give you, in order to improve the robustness of your code, you can match each line with a regular expression. In this way you can be sure your line is formatted exactly how you need.
For example:
std::regex line_pattern("\\s{6}[0-9]+\\s[^\\n]+");
if (std::regex_match(line, line_pattern) == false) {
// ups... the line is not formatted how you need
// this is an error
}
I'm trying to read a file of int's and double's into a vector but I am having difficulty doing so. Given something like:
1 2.1 3 4
2 4
3
9 0.1
How can I use ifstream and the getline function to convert the string into integers and doubles & inserting this into a vector?
I know this is incorrect but I am thinking of something along the lines of:
vector<Pair *> vec; //Pair is a class that contains a int & a double data member
string str;
double num;
ifstream f;
f.open("name of file");
while(getline(f, str){
num = stod(str);
}
To insert into the vector I believe I can do something along the lines of:
Pair * pairObj = new Pair(x,y); //"x" being of type int and "y" being of type double
v.push_back(pair);
I'm sorry if this is unclear, please let me know and I will do my best to explain myself.
You should just use stream iterators!
#include <iostream> // for IO
#include <vector> // for vector!
#include <iterator> // for stream iterator
#include <algorithm> // for copy (optional)
if you are directly initializing
vector<double>vdata{istream_iterator<double>(ifile),
istream_iterator<double>()};
else use copy or copy_n if you only want a fixed amount of data
copy(istream_iterator<double>(ifile),
istream_iterator<double(),
back_inserter(vdata));
if you are working with a large file i would recommend using this method
vector<doube>vdata;
// this will save alot of time, if you don't resize the vector must keep reallocating data
vdata.reserve(file_size);
copy(istream_iterator<double>(ifile),
istream_iterator<double>(),
back_inserter(vdata));
strtod() is C. Proper C++ uses the >> operator.
Once you have read each line of text, construct a std::istringstream from the string, then use operator>> to parse it.
Something along these line::
std::ifstream f("name of file");
// Check if the file was succesfully opened, etc...
std::string str;
while( getline(f, str))
{
std::istringstream i(str);
std::vector<double> v;
double d;
while (i >> d)
{
v.push_back(d);
}
if (!i.eof())
{
// Must be a parsing failure, deal with it in some way.
}
else
{
// Otherwise, v is the vector of numbers on this line.
}
}
string str;
std::vector< double> vd;
// loop reading lines of input
while( getline( f, str )
{
std::stringstream sst(str);
std::string a;
// loop reading space separated values in line
while( getline( sst, a, ' ' ) )
// conver to double and add to end of vectior
vd.push_back( stod( a );
}
// check for complete pairs
if( vd.size() % 2 )
cout << "Error!"
// loop over pairs
vector< pair<int,double> > vpairs;
for( int kp = 0; kp < vd.size()/2; kp++ )
vpairs.push_back( pair<int,double>( (int)vd[kp*2],vd[kp*2+1) );
I am trying to set a variable to the value of an element of a 2D array. This should be easy, but whenever I write it I get 0 in the variable. I read in a file to put in the array elements manually, which might be causing the problem, but I am not sure what's wrong.
Here is my code:
int main(){
//declaring all the variables
vector < vector <double> > data; // vector of vectors to hold the data.
int z=0;
int z1,z2;
//open the input file as an input file stream (ifstream)
ifstream dataFile;
dataFile.open( "GBplaces.csv" );
//if the file is open...
if (dataFile.is_open()) {
// and while it's not the end of the file...
while (!dataFile.eof() ){
z++;
if (z==1){
string aLine;
getline ( dataFile, aLine );
printf ("place, type, population, lattitude, longitude \n\n");
}
else if(z==102){
string aLine;
getline ( dataFile, aLine );
}
else {
//read in a line of the file and put the ontents into the arays.
string aLine; // hold the read in line
getline ( dataFile, aLine ); //reads line from dataFile to aLine
//split up the string aLine based on where the comma is
int comma;
int nextCom=0;
//comma_pos = aLine.find(',',0); //finds where the comma is, starting from the begining ie 0
string xst, yst, zst; //temp variables for column
vector <double> temp; // tempory vector for the points
double xt, yt, zt;
comma = aLine.find(',',0); //find first position of comma
xst = aLine.substr(0,comma); // extracts string subvalue
temp.push_back(atof(xst.c_str())); //add value to end of temporary vector
comma += 1; // add 1 to the comma position count
while (aLine.find(',',comma) != -1) {
// find middle values
if(aLine==""){}
else{
nextCom = aLine.find(',',comma);
yst = aLine.substr(comma, nextCom - comma);
temp.push_back(atof(yst.c_str())); //convert string into double and add it to the end of the vector
comma = nextCom + 1;
}
}
// same calculations as in the loop but for the last value after the comma
zst = aLine.substr(nextCom + 1, aLine.length());
temp.push_back(atof(zst.c_str()));
// push temporary vector onto data vector
data.push_back(temp);
}
}
}
z = data[3][3].
When I run the program I get z=0, although when I print the table, the element is 51.26.
Update:
Found the error:
int z=0;
int z1,z2;
z1,z2 should be doubles instead of integers. This was messing up the rest of the number
I am trying to use std::getline() in my project to read in a text file into an array of strings.
Here is my code:
ifstream ifs ( path );
string * in_file;
int count = 0;
while ( !ifs.eof() )
{
++count;
if ( count == 1 )
{
in_file = new string[1];
}
else
{
// Dynamically allocate another space in the stack
string *old_in_file = in_file;
in_file = new string[count];
// Copy over values
for ( int i = 0 ; i < ( count - 1 ) ; i++ )
{
in_file[i] = old_in_file[i];
}
delete[] old_in_file;
}
// After doing some debugging I know this is the problem what am I
// doing wrong with it?
getline(ifs,in_file[count - 1]);
}
So after doing some decoding I know that the getline() is not placing any value in the array of strings. It seems to place a null string in the array.
The goal is to read in a text file like:
Hello
Bye
See you later
The array will be filled like:
in_file [0] = Hello
in_file [1] = Bye
in_file [2] = See you later
Never wrap reading from the stream with the following loop:
while ( !ifs.eof() )
At some websites, you will find an example telling you to do:
while ( ifs.good() )
which is a bit better than the first loop, yet still it is quite error prone and not advisable to do. Have a look at: Why is iostream::eof inside a loop condition considered wrong?
The most common ways of reading the files are either using std::getline when reading by lines:
std::string line;
while ( std::getline(ifs, line) ) {
if (line.empty()) // be careful: an empty line might be read
continue;
...
}
or simply using >> operator when reading by words or extracting concrete types (e.g. numbers):
std::string word;
while ( ifs >> word ) {
...
}
And to your dynamically allocated C-style array of std::string objects: avoid dynamic allocation as much as possible. Believe me, you don't want to take care of memory management on your own. Prefer using objects with automatic storage duration. Take advantage of what the standard library provides.
As it was pointed out already: use STL containers such as std::vector instead of C-style arrays:
std::ifstream ifs(path);
std::vector<std::string> lines;
std::string line;
while ( std::getline(ifs, line) )
{
// skip empty lines:
if (line.empty())
continue;
lines.push_back(line);
}
Why so trouble ?
Simply use std:vector of std::string
std::string str;
std::vector <std::string> vec;
while ( std::getline(ifs,str) )
{
vec.push_back(str) ;
}
If you really need an array of string
do :
string * in_file = new string[vec.size()];
And copy the elements from vec to in_file
for(size_t i=0;i<vec.size();i++)
in_file[i] = vec[i];
This question already has answers here:
Edit a specific row in a file
(5 answers)
Closed 6 years ago.
I have a txt file like this:
"shoes":12
"pants":33
"jacket":26
"glasses":16
"t-shirt":182
I need to replace the number of jacket ( from 26 to 42 for example ). So, I have wrote this code, but I don't know how to edit a specific row where there is the word "jacket":
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream f("file.txt");
string s;
if(!f) {
cout< <"file does not exist!";
return -1;
}
while(f.good())
{
getline(f, s);
// if there is the "jacket" in this row, then replace 26 with 42.
}
f.close();
return 0;
}
In order to modify data in a text file, you'll generally have to read
the entire file into memory, make the modifications there, then rewrite
it. In this case, I'd suggest defining a structure for the entries,
with name and quantity entries, equality defined as equality of the
names, and an overloaded operator>> and operator<< to read and write
it from the file. You're overall logic would then use functions like:
void
readData( std::string const& filename, std::vector<Entry>& dest )
{
std::ifstream in( filename.c_str() );
if ( !in.is_open() ) {
// Error handling...
}
dest.insert( dest.end(),
std::istream_iterator<Entry>( in ),
std::istream_iterator<Entry>() );
}
void
writeData( std::string const& filename, std::vector<Entry> const& data )
{
std::ifstream out( (filename + ".bak").c_str() );
if ( !out.is_open() ) {
// Error handling...
}
std::copy( data.begin(), data.end(), std::ostream_iterator<Entry>( out ) );
out.close();
if (! out ) {
// Error handling...
}
unlink( filename.c_str() );
rename( (filename + ".bak").c_str(), filename.c_str() );
}
(I'd suggest raising exceptions in the error handling, so that you don't
have to worry about the else branches of the ifs. Except for the
creation of the ifstream in the first, the error conditions are exceptional.)
First of all, this is not possible in the naive way. Let's say you want to edit said row but write a larger number, there won't be any space in the file. So usually eidts in the middle are done by rewriting the file or writing a copy. Programs may use memory, temp files, etc and hide this from a user, but chaning some bytes in the middle of a file will only work in very restircted environments.
So what you'll want to do is write another file.
...
string line;
string repl = "jacket";
int newNumber = 42;
getline(f, line)
if (line.find(repl) != string::npos)
{
osstringstream os;
os << repl << ':' << newNumber;
line = os.str();
}
// write line to the new file. For exmaple by using an fstream.
...
If the file has to be the same, you can read all lines to memory, if there is enough memory, or use a temp file for either input or output.