Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » sscanf equivelant for std::string

Credits go to Trent Gamblin for helping out!
This thread is locked; no one can reply to it. rss feed Print
sscanf equivelant for std::string
Steve Terry
Member #1,989
March 2002
avatar

I am trying to parse through a post script file and basically am rotating it 90 degrees. I have the methods to do so and all it involves is flipping width and height, adding one line to rotate, and translating by negative height. I was using fstream.getline and reading into a char array of 4096 chars... which in at least one instance overflowed the buffer, this caused a flag to be set and getline never returned anything afterwards, essentially I went into an infinite loop. The reason I was reading into a char array rather than a std::string was the ease of sscanf in parsing the lines. I now found a different getline call which uses std::string and the overflow issue is gone, however when it comes to something like sscanf C++ lacks. What I did use was stringstream and treated the string as a stream object like cin or cout and I got my values but it's not very elegant. For example:

// C
sscanf(buffer, "some command:[%f %f] other stuff", &val1, &val2);

I have no idea how to do the same in C++ using strings. If I convert it to a stringstream and do:
mystream >> std::string command;
cout << command << endl;
I would get "some" which is not what I want.

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Trent Gamblin
Member #261
April 2000
avatar

C++ Strings have a method called c_str that returns a C-type string equivalent of the string.

std::string s;
char* c_string = s.c_str();

Maybe you can use that with sscanf?

Steve Terry
Member #1,989
March 2002
avatar

Yes I realize I could do that as well, convert it to a char array, use sscanf on it, allocate a new char array of size of buffer + 1, sprintf, then spit that out to the output file. I was hoping for something more elegant maybe :-/

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Trent Gamblin
Member #261
April 2000
avatar

Regular expressions would be perfect IMO.

Steve Terry
Member #1,989
March 2002
avatar

Like boost? I've seen some examples and it looks like overkill, not to mention I couldn't tell what it was doing :P Any examples?

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Trent Gamblin
Member #261
April 2000
avatar

Well I don't know anything about postscript commands so I don't know if this would be useful but just as an example in Perl, to swap the two floats in your example you could use an expression like this:

$s =~ s/some command:[([0-9.]+) ([0-9.]+)] other stuff/some command:[\2 \1] other stuff/g

In C++ it's almost the same thing, maybe an extra function call to create an expression or something. Then you'd just print out s. Or you could capture the floats into variables and use them later by replacing the \1 and \2 with $var1/$var2:

$s =~ m/some command:[([0-9.]+) ([0-9.]+)] other stuff/;
$var1 = $1;
$var2 = $2;

$s =~ s/some command:[([0-9.]+) ([0-9.]+)] other stuff/some command:[$var3 $var4] other stuff/g

You can match anything easily with regular expressions. It's learning them that's the (somewhat but not really) tricky part. "Mastering Regular Expressions" is a great book. It can easily save you way more time than it takes to read it if you use them regularly. I wouldn't use a text editor that doesn't support regular expressions.

[edit]
Yes, like boost. And if you like I can explain what those expressions mean or you can look up some texts on the internet.

Steve Terry
Member #1,989
March 2002
avatar

I know what regular expressions are :) I found some better boost examples, but I was hoping for something built into C++, but am I right in thinking that boost will be Incorporated into C++ before too long?

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Carrus85
Member #2,633
August 2002
avatar

Unfortunately, this is one of the main weak points of the C++ standard library; there is really no sscanf equivilant... period. Basically, you have to do it by yourself. In that particular example you gave us, this will do the job:

std::string foo = "some command:[10.0 99.9] other stuff...";
float a = 0, b = 0;
size_t left_bound = foo.find('[',0) + 1;
size_t count = foo.find(']',left_bound) - left_bound;
stringstream bar;
bar << foo.substr(left_bound, count);
bar >> a >> b;

Of course, in general, you can emulate sscanf if necessary (pseudo-code)

std::string scanf_code = "foo bar %d %d hello %d"
// Translates to:
    eat "foo bar " from input;
    read int from input;
    read int from input;
    eat "hello " from input;
    reat int from input;

Something like this (probably not the most efficent method, admittantly...)

// Example:
std::string input = "foo bar 10 20 hello 30"
int a,b,c;
std::string garbage;
stringstream foo;
foo << input;
input >> garbage >> garbage >> a >> b >> garbage >> c;

Trent Gamblin
Member #261
April 2000
avatar

Yes, regular expressions and other parts of boost are being considered to be part of standard C++.

Erkle
Member #3,493
May 2003
avatar

I can't see what's wrong with:
sscanf(s.c_str(), "some command:[%f %f] other stuff", &val1, &val2);

But if its for some kind of script or something then try looking into Boost.Spirit.

Something like:

float x, y;
rule<> my_rule = str_p("some command:[")
    >> real_p[assign_a(x)]
    >> real_p[assign_a(y)]
    >> str_p("]");
if(parse(buffer, my_rule, space_p).full)
{
    // ToDo: Do something with the results;
}

Warning: Boost.Spirit can be difficult to understand at the best of times but it is useful enough to make up for it.

If the writing above has offended you, you've read it wrong.....fool.
And if you read that wrong it means 'All of the above is opinion and is only to be treated as such.'

Bob
Free Market Evangelist
September 2000
avatar

Why use boost::spirit when boost::regexp will do?

--
- Bob
[ -- All my signature links are 404 -- ]

Thomas Fjellstrom
Member #476
June 2000
avatar

totally serious: Why use Boost::Anything when some simple char/text greping will do?

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

CGamesPlay
Member #2,559
July 2002
avatar

Quote:

Why use Boost::Anything when some simple char/text greping will do?

I agree. I prefer Carrus' (first) method so far over anything else so far in this thread.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Go to: