I can't believe I'm even having to ask this rather simple question but I wouldn't normally use C++ for this, and I'm caught on a snag.

I have some files filled with many entries like this (from unix time command):

real	0m0.475s
user	0m0.091s
sys	0m0.028s

For each line I would like to strip out the minutes and the seconds as an integer and a double respectively, discarding the real/user/sys string, the whitespace, the 'm', and the 's'.

I need to do it in C++...
I have tried to fiddle around with fscanf but with little avail. I would want to write something like...

char rubbish[32]; int mins; double secs;

while (fscanf(pFile, "%s%dm%lfs",rubbish,mins,seconds)!=EOF)
{
	...
}

I realise this isn't the correct way of using format specifiers and that I should have a regular expression in there for the m and the s, however it serves for illustration.

Can someone help me out?

1. Use filestreams.

fstream in_file("/path/to/your/file.foo");

2. Use a loop with getline() to read out all the lines.

std::string buffer = "";
while (getline(in_file, buffer)) { // <-- will automaticly stop at end of file
    // "buffer" now contains a line
}

3. You need to parse out the values. You could use find to locate them in your buffer/line

4. Convert the value to int or double. Use stringstreams please, not atoi.

Edited 6 Years Ago by Nick Evan: n/a

I completely agree with Nick Evan.
Use Filestream and Stringstream.

(f)scanf, atoi and relatives are C, not C++.

Take a look at this code.
I'm not sure if it will work, as I never use tabs, but I suppose \t should do it:

std::string line;
// get a line from the file
std::string::size_type whitespace = line.find('\t');
if(whitespace == std::string::npos)
   ; // quit or something.. we expect a whitespace

std::string name = line.substr(0, whitespace); // the first part

std::string::size_type min = line.find("m", whitespace); // search for m after whitespace
if(min == std::string::npos)
    ; // quit or something, we expected m

std::string minutes = line.substr(whitespace+1, min-(whitespace+1)); // get content from after whitespace, till m.

Here's a litte bit of code that will help with your string/number conversion:

#include <string>
#include <iostream>
#include <sstream>
#include <iomanip>

/** Converts a number to a string
  * @param  number - The number to convert
  * @param  prec   - Floating point precision to use
  * @param  w      - Width of the string
  * @return A string representation of the number
  */
template <class T>
std::string num2str( T number, int prec=2, int w=0 )
{
    std::ostringstream ss;
    ss.setf( std::ios::showpoint | std::ios::fixed );
    ss.precision( prec );
    ss.fill( ' ' );
    ss.width( w );
    ss << number;
    return ss.str();
}

/** Converts a string to a number
  * @param  str    - The string to convert
  * @param  number - The storage for the number
  */
template <class T>
void str2num( std::string str, T &number )
{
    std::istringstream ss( str );
    ss >> number;
}

using namespace std;

void test()
{
    int testInt;
    double testDbl;
    string testStr;
    
    testStr = num2str( "42.00001" );
    cout << "testStr=" << testStr << endl;

    str2num( "81.9954", testDbl );
    cout << "testDbl=" << testDbl << endl;

    str2num( "-42", testInt );
    cout << "testInt=" << testInt << endl;
}

The num2str and str2num functions would normally go in my tools.h header file that is filled with all sorts of useful goodies. Give it a try!

As far as extracting the data from the input, I would want to use a regular expression for that. I know it's a simple case you could probably parse by hand, but regular expressions are the correct tool for the job. The boost library and Qt both have regular expressions, and both are readily available online.

there are many ways to do it .
another way is to use substr() function from string streem it taks 2 arguments.
its much easyer to do it in this way..
gust read in substr function :)

@dusktreader: You can combine your convert code into 1 :

template<typename ReturnType, typename InputType>
ReturnType convertTo(const InputType& in){
 std::stringstream ss;
 ss << in;
 ReturnType ret = ReturnType();
 if( (ss >> ret).fail()) throw std::exception("Conversion failed");
 return ret;
}

int main(){
 float pi = convertTo<float>("3.1415");
 string strPi = convertTo<string>(pi);
}

@dusktreader: You can combine your convert code into 1 :

template<typename ReturnType, typename InputType>
ReturnType convertTo(const InputType& in){
 std::stringstream ss;
 ss << in;
 ReturnType ret = ReturnType();
 if( (ss >> ret).fail()) throw std::exception("Conversion failed");
 return ret;
}

int main(){
 float pi = convertTo<float>("3.1415");
 string strPi = convertTo<string>(pi);
}

Very nice. I like this.

This article has been dead for over six months. Start a new discussion instead.