Reputation: 155
I have a data file which is text format. It has 2 coloums first one is not useful that I could ignore it and second one is that what I need. The coloum has a different values on each row as string, float etc. For some calculation I need to only float members of this coloum. I followed that way, first declare a float array and read values and save the array with ">>" basic command.
Problem is when non-float row has came, reading function works as broken. It reads non-float values as "0" and save as that. It's OK but after that reads whole values as "0" even if it was a float.
Datafile.txt (example)
aa 1.1
bb 2.2
cc 3.0
dd somestring
ee 4.3
ff 4.9
Code (example)
do
{
dfile >> a >> dat[i];
ofile << dat[i]<<endl;
cout << dat[i]<<endl;
i++;
}while(dfile.eof());
Output file (example)
1.1
2.2
3.0
0
0
0
..goes
I've thought two ways to solve the problem. First one is skipping non-float rows. Second one is reading row in a period. Because float values listed in a sequence.
Upvotes: 0
Views: 1844
Reputation: 11
using getline and regex_token_iterator
#include <regex>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
std::vector<float> v;
std::regex reg("-?\\d+(\\.\\d+)?");
const char* filename="myfile.txt";
std::ifstream ifs(filename,std::ios::binary);
for(std::string s;std::getline(ifs,s);)
for(std::sregex_token_iterator rgi(s.begin(),s.end(),reg);rgi!=std::sregex_token_iterator();++rgi)
v.push_back(std::stof(rgi->str());
std::copy(v.begin(),v.end(),std::ostream_iterator<float>(std::cout," ");
return 0;
}
Upvotes: 1
Reputation: 1429
I would use an algorithm like this:
For each line in the file:
Upvotes: 1
Reputation: 27538
It's OK but after that reads whole values as "0" even if it was a float.
You haven't shown your full code, but this sounds like the input stream is in an error state after the first non-parseable floating-point number, so it stops reading anything at all.
As for a solution to the problem, read every line as a std::string
, then split the line into a std::vector<std::string>
. If the vector doesn't contain two elements or if the second one is not a double
, do nothing, else process the row.
Something like this:
std::string line;
while (std::getline(dfile, line))
{
auto const elements = parse(line);
if (size(elements) == 2 && is_double(elements[1]))
{
// process
}
}
Now that you have solved the problem on the higher abstraction level, all you have to do is implement something like parse
and implement something like is_double
(divide & conquer).
Also note that the default C++ floating-point type is double
and not float
. When in doubt, use double
.
Upvotes: 1
Reputation: 66441
Read a string first, then attempt to convert to a number:
std::string maybeNumber;
while (dfile >> a >> maybeNumber)
{
std::istringstream is(maybeNumber);
float number = 0.0f;
if (is >> number)
{
dat[i] = number;
i++;
}
}
(You don't want to use eof
. Everyone thinks they want to use eof
, but it's almost always not what they need. See this question for details.)
Upvotes: 2