agenel
agenel

Reputation: 155

Reading only float values from text file

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

Answers (4)

brenxthecpdev
brenxthecpdev

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

Detonar
Detonar

Reputation: 1429

I would use an algorithm like this:

For each line in the file:

  1. Split the string by whitespaces
  2. For each result of this split:
    1. Macht with regex "^\d+(\.\d+)?$"
    2. If string matches regex, convert to float and save in result array

Upvotes: 1

Christian Hackl
Christian Hackl

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

molbdnilo
molbdnilo

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

Related Questions