Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Help with sscanf() needed desperately

Reply
Thread Tools

Help with sscanf() needed desperately

 
 
Artemio
Guest
Posts: n/a
 
      07-29-2006
Dear folks,

I need some help with using the sscanf() function. I need to parse a
string which has several parameters given in a "A=... B=... C=..." way,
and each has a different type (one is a text string, another is a
decimal, next one is float, etc.).

I have GCC 4.0.1 on Mac OS X Tiger.

Here is an example of what I am trying to do.

<code>

char A[16];
int B;
float C;

sscanf( "A=Test B=25 C=3.14159", "A=%s B=%d C=%f", A, &B, &C);

printf("%s %d %f",A,B,C);

</code>

This prints "Test 0 0.0000"

I also tried this:

<code>
....
sscanf( "A=Test B=25 C=3.14159", "A=%s",A);
sscanf( "A=Test B=25 C=3.14159", "B=%d",&B);
sscanf( "A=Test B=25 C=3.14159", "C=%f",&C);
....
</code>

but this gives same results...

What am I doing wrong? :-/


Thanks for any help.

Artemiy.

 
Reply With Quote
 
 
 
 
Szabolcs Borsanyi
Guest
Posts: n/a
 
      07-29-2006
On Sat, Jul 29, 2006 at 11:58:34AM -0700, Artemio wrote:
> Dear folks,
>
> I need some help with using the sscanf() function. I need to parse a
> string which has several parameters given in a "A=... B=... C=..." way,
> and each has a different type (one is a text string, another is a
> decimal, next one is float, etc.).
>
> I have GCC 4.0.1 on Mac OS X Tiger.
>
> Here is an example of what I am trying to do.
>
> <code>
>
> char A[16];
> int B;
> float C;
>
> sscanf( "A=Test B=25 C=3.14159", "A=%s B=%d C=%f", A, &B, &C);
> printf("%s %d %f",A,B,C);
> </code>


> This prints "Test 0 0.0000"


Surrounding it with a main() {...} and adding the header include, I failed
to reproduce your problem (probably on the same system as yours).

> I also tried this:
>
> <code>
> ...
> sscanf( "A=Test B=25 C=3.14159", "A=%s",A);
> sscanf( "A=Test B=25 C=3.14159", "B=%d",&B);
> sscanf( "A=Test B=25 C=3.14159", "C=%f",&C);
> ...
> </code>


This one con better understand: sscanf does not keep the position information
within the string between subsequent calls. It always starts form the beginning
"A=...", so there is no match in the second and third line.
In case of a stream (file), it is a completely different story, then you
use fscanf and you will find the expected behaviour.

By the way: you could check the return value of sscanf (if you are interested
in handling erroneous cases).

If you split your string into a white separated list, or you get it already
so (e.g. from argv, the 2nd argument of main()), you can use the macros

#define dopt(name) sscanf(*argv,#name " = %lf",&name)
#define iopt(name) sscanf(*argv,#name " = %d",&name)
#define sopt(name,size) sscanf(*argv,#name " = %" #size "s",name)

I have in my parsing routine a line
while(*++argv) sopt(A,16) || iopt(B) || dopt(C) || fprintf(stderr,"No!\n");

Consider limiting the size of the read string as you see in the third macro.

Hmm, did it help anything?

Szabolcs Borsanyi
 
Reply With Quote
 
 
 
 
Michael Mair
Guest
Posts: n/a
 
      07-29-2006
Artemio schrieb:
> Here is an example of what I am trying to do.
>
> <code>
>
> char A[16];
> int B;
> float C;
>
> sscanf( "A=Test B=25 C=3.14159", "A=%s B=%d C=%f", A, &B, &C);
>
> printf("%s %d %f",A,B,C);
>
> </code>


It is most of the time a good idea to copy&paste an actual
compiling minimal example showing your problem. With the following,
I obtain the desired results:

#include <stdio.h>

int main (void)
{
char A[16];
int B;
float C;

if (3 == sscanf("A=Test B=25 C=3.14159",
"A=%15s B=%d C=%f",
A, &B, &C)
)
{
printf("%s %d %f\n",A,B,C);
}

return 0;
}

Note
a) the inclusion of <stdio.h> to have prototypes of
printf() and sscanf() in scope
b) checking the return value of sscanf() to make sure that
all conversions were successful
c) the '\n' as last output character to make sure that the
output actually happens (without, this is not guaranteed).

> This prints "Test 0 0.0000"


My version using your printf() and a slightly altered sscanf()
call prints
Test 25 3.141590

> I also tried this:
>
> <code>
> ...
> sscanf( "A=Test B=25 C=3.14159", "A=%s",A);
> sscanf( "A=Test B=25 C=3.14159", "B=%d",&B);
> sscanf( "A=Test B=25 C=3.14159", "C=%f",&C);
> ...
> </code>


This is wrong.

> What am I doing wrong? :-/


I cannot tell -- you did not give us said complete programme.


Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
 
Reply With Quote
 
Artemio
Guest
Posts: n/a
 
      07-30-2006
Hello guys, and thanks so much for the replies!

Here come my questions:

1. I am trying to parse a line this way:

char WaveType[2];
float B0, B1;
int Angle, Repeat;

sscanf( Line, "W=%s a=%d R=%d B0=%f B1=%e", WaveType, &Angle, &Repeat,
&B0, &B1);

The "Line" string contains:

W=TE a=45 R=3 B0=1.0 B1=1e-9

Now the WEIRD thing: when I do it like above it WORKS, but if I read
this string from a file line-by-line, and one of the lines is like
this, it DOESN'T work! Only the WaveType variable gets it's data
properly.

E.g.

while( fgets( Line, sizeof Line, File ) != NULL ){
sscanf( Line, "W=%s a=%d R=%d B0=%f B1=%e", WaveType, &Angle,
&Repeat, &B0, &B1);
}

:-/

2. What is the best way to read this line from a file and parse it into
variables defined above, but in a random order? E.g. sometimes the
string may be W=TE a=45 R=3 B0=1.0 and next time it'll look like W=TE
R=3 B0=1.0 a=45.


Thanks again,

Artemiy.

 
Reply With Quote
 
Artemio
Guest
Posts: n/a
 
      07-30-2006
Hey guys, sorry, reading with sscanf( Line, "W=%s a=%d R=%d B0=%f
B1=%e", WaveType, &Angle, &Repeat, &B0, &B1) works fine, it appears the
data was not printed in a correct way, that's all.

Anyway, the important thing now, what is the best way to parse the Line
string if the order of these X=... variables can change?

Thanks again,

Artemiy.

 
Reply With Quote
 
Chris Torek
Guest
Posts: n/a
 
      07-30-2006
In article <(E-Mail Removed). com>
Artemio <(E-Mail Removed)> wrote:
[question 1 already solved, turned out to be error elsewhere]

>[In general, a] "Line" string contains [something like]:
> W=TE a=45 R=3 B0=1.0 B1=1e-9

[which can be read relatively easily with sscanf().]
>
>2. What is the best way to read this line from a file and parse it into
>variables defined above, but in a random order? E.g. sometimes the
>string may be W=TE a=45 R=3 B0=1.0 and next time it'll look like W=TE
>R=3 B0=1.0 a=45.


Your best bet is probably to write your own "line parser". You
have a number of decisions to make:

- What happens if a line is malformed?

W==1=1=1=47= R:hello, B0=1.2.3.4

- What happens if a line is missing one or more values?

W=TE B1=1.0 R=3 # but no value for "a" or "B0"

If all entries are of the form <text1>=<text2>, where text1 and
text2 never contain any whitespace, you can easily break up a line
into whitespace-separated groups, then break up the broken-up parts
into "="-separated pieces, then look up the <text1> part to see
whether it is "W", "a", "R", "B0", or "B1". The result of that
will determine how the <text2> part is to be treated (as a "word"
for W, as an integer for "R" and "a", and as a floating-point value
for B0 and B1).

Although the strtok() function is quite ugly, it happens to be
fairly well suited for the first task. The second can be done
with a simple "strchr" (do not use strtok() inside the outer
loop!):

#include <string.h>
...
#define WHITESPACE " \t\n" /* add \b \r \f \v if desired */
...

/* handle one line of input */
char *entry, *value;

for (entry = strtok(line, WHITESPACE); entry != NULL;
entry = strtok(NULL, WHITESPACE)) {
value = strchr(entry, '=');
if (value == NULL)
... do something about malformed entry ...

/* wipe out "=" and leave "value" pointing to the value */
*value++ = 0;

if (strcmp(entry, "W") == 0)
... handle W value ...
else if (strcmp(entry, "a") == 0)
... handle "a" value ...
else if (strcmp(entry, "R") == 0)
... handle R value ...
else if (strcmp(entry, "B0") == 0)
... handle B0 value ...
else if (strcmp(entry, "B1") == 0)
... handle B1 value ...
else
... do something about unknown variable ...
}
... check to make sure all 5 values were specified, if needed ...
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
 
Reply With Quote
 
Artemio
Guest
Posts: n/a
 
      07-30-2006
Wow Chris, thank you *so* much for the suggestions! I learned strtok()
a bit but never managed to write anything working with it. Thanks a lot
again, I will learn your code.

 
Reply With Quote
 
Szabolcs Borsanyi
Guest
Posts: n/a
 
      07-30-2006
> Artemio wrote:
>
> Here come my questions:
> 1. I am trying to parse a line this way:
>
> char WaveType[2];
> float B0, B1;
> int Angle, Repeat;
>
> sscanf( Line, "W=%s a=%d R=%d B0=%f B1=%e", WaveType, &Angle, &Repeat,
> &B0, &B1);
>
> The "Line" string contains:
>
> W=TE a=45 R=3 B0=1.0 B1=1e-9



Hmm, you are filling a 3-char-long string into a two-char-long array.
If you are lucky, the final NUL written after WaveType does not affect
other variables (alignment holes), but this is still an undefined behaviour.

> while( fgets( Line, sizeof Line, File ) != NULL ){
> sscanf( Line, "W=%s a=%d R=%d B0=%f B1=%e", WaveType, &Angle,
> &Repeat, &B0, &B1);
> }


Well, that's it. You are reading from a file. So my previous posting in the
thread can work in arbitrary order. (But you don't know if an entry is
in the same line or in then next one.)

After you tokenized with strtok or simply with

while( fgets( Line, sizeof Line, File ) != NULL ){
char tokens[8][9]; /* suppose you have at most 8 fields, rest ignored */
int i,s;
/* give default values to your parameters */
s=sscaf(line,"%9s %9s %9s %9s %9s %9s %9s %9s", /* type a lot */
tokens[0],tokens[1],.... );
/* no space between '=' and name and value*/
for(i=0;i<s;i++) {
/* here come my dopt,iopt, sopt macros */
/* read the parameters in the order they appear in the file */
}
}

If you know that you do not accept more than say 8 fields, each 8 char long,
this is (perhaps) the simplest way for random field order.

Szabolcs Borsanyi
 
Reply With Quote
 
Default User
Guest
Posts: n/a
 
      07-30-2006
Artemio wrote:

> Wow Chris, thank you so much for the suggestions! I learned strtok()
> a bit but never managed to write anything working with it. Thanks a
> lot again, I will learn your code.



Please quote enough of the previous message for context. Google does
that automatically now. Your replies belong following or interspersed
with properly trimmed quotes. See the vast majority of posts here for
examples.




Brian
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Help Desperately Needed Posting to Usenet Through Google Ashley Endicott Computer Support 29 11-16-2007 04:35 AM
Multi Level Forms Authentication Help DESPERATELY NEEDED! Joe Rigley ASP .Net 2 05-12-2005 05:03 PM
Scanner/Apple help desperately needed Grady R. Thompson Digital Photography 6 09-15-2004 06:35 PM
Help with Script Needed Desperately Joe Foran Perl 0 08-31-2004 10:43 PM
Help desperately needed Els HTML 14 07-22-2004 02:51 AM



Advertisments