string.scanf?

J

JustSomeGuy

I have a string that looks like:
"123.45:123.45"
I am using sscanf "%f%*c%f" to extract the two floats and ignore the colon.
However there may be more than two floats....
Is there perhaps a better way to do this in C++?
Like make the string appear as a stream and do it with operator>>

string x;
float f1, f2;
x >> f1;
x >> f2;
 
Q

qWake

JustSomeGuy said:
I have a string that looks like:
"123.45:123.45"
I am using sscanf "%f%*c%f" to extract the two floats and ignore the colon.
However there may be more than two floats....
Is there perhaps a better way to do this in C++?
Like make the string appear as a stream and do it with operator>>

string x;
float f1, f2;
x >> f1;
x >> f2;

What you are doing is trying to separate tokens that are part of a string.
Lookup the C "strtok" function that will do that for you quite simply. Read
the input in a C-style string and parse it with strtok. Your program can
count the tokens as it goes, you just convert them to float with something
like "atof" or any other way you like.
 
E

E. Robert Tisdale

JustSomeGuy said:
I have a string that looks like:

I am using sscanf "%f%*c%f"
to extract the two floats and ignore the colon.
However there may be more than two floats....
Is there perhaps a better way to do this in C++?
Like make the string appear as a stream and do it with operator>>
cat main.cc
#include <iostream>
#include <sstream>
#include <cstdlib>

int main(int argc, char* argv[]) {
std::string x("123.45:123.45");
std::istringstream iss(x);
const
size_t n = 2;
float f[n];
size_t j = 0;
while (iss >> f[j]) {
std::cout << f[j]
<< " = f[" << j << "]" << std::endl;
++j;
char c = '\0';
if (iss >> c && ':' == c)
continue;
else
break;
}
return EXIT_SUCCESS;
}
g++ -Wall -ansi -pedantic -o main main.cc
./main
123.45 = f[0]
123.45 = f[1]
 
P

Phlip

JustSomeGuy said:
I have a string that looks like:
"123.45:123.45"
I am using sscanf "%f%*c%f" to extract the two floats and ignore the colon.
However there may be more than two floats....
Is there perhaps a better way to do this in C++?
Like make the string appear as a stream and do it with operator>>

string x;
float f1, f2;
x >> f1;
x >> f2;

I recently refactored this ugly code:

typedef std::map<string, string> params_t;

bool
Product(params_t & testCase)
{
double num (strtod(testCase["Input1" ].c_str(), NULL));
double den (strtod(testCase["Input2"].c_str(), NULL));
double quo (strtod(testCase["Product()" ].c_str(), NULL));

return num * den == quo;
}

It now looks like this:

static double
getDouble(params_t & testCase, string columnName)
{
double num(double());
std::stringstream z (testCase[columnName]);
if (z >> num)
return num;
return 0.0; // TODO will throw soon
}

bool
Product(params_t & testCase, string & because)
{
double num (getDouble(testCase, "Input1" ));
double den (getDouble(testCase, "Input2" ));
double quo (getDouble(testCase, "Product()"));

return num * den == quo;
}

Focus on the 'streamstring z' deep inside. One might extract your floats
using:

string x;
stringstream z(x);
double f1, f2;
char space;
z >> f1;
z >> space;
z >> f2;

BTW use 'double' without a reason to use 'float', just as one uses 'int'
without a reason to use 'short' or 'long'. On modern CPUs 'double's can be
faster, too.

My refactor replaced redundant calls to strtod() (another way to do it) with
a single call to operator>>().
 
J

Jorge Rivera

JustSomeGuy said:
I have a string that looks like:
"123.45:123.45"

I have two suggestions:

This first one uses a dummy character to use istringstreams capabilities
for parsing...
(You can extend this to more floats by iterating until iss fails....)

using namespace std;
string x("123.45:123.46");

char colon; // Store the colon (or any other character)
float f1, f2; // Our target floating numbers

//Initialize an istringstream
istringstream iss(x);

// Extract the tokens
iss>>f1>>colon>>f2;

The second approach uses the strings find function to figure out the
location of the colons, then send the substring to isstream

string x("123.45:123.46:305.37");
istringstream iss("");
vector<double> mFloats;
string::size_type next_colon;
float temp = 0.0f;

x = std::string("3.0");
do
{
next_colon = x.find(':'); // Find next colon
iss.clear(); // Needed to reuse iss
iss.str(x.substr(0, next_colon)); // Use the first token
x = x.substr(next_colon+1); // Update x (You may want to use a temp
string)
iss>>temp; // Extract the current float
mFloats.push_back(temp); // Add float to the vector
}while(string::npos != next_colon);

// Output the elements
size_t doubles = mFloats.size();
cout<<"Found "<<doubles<<" number..."<<endl;
for(size_t i=0; i<doubles; i++)
{
cout<<"\t"<<i<<": "<<mFloats<<endl;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top