Help with sscanf() needed desperately

Discussion in 'C Programming' started by Artemio, Jul 29, 2006.

  1. Artemio

    Artemio Guest

    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.
     
    Artemio, Jul 29, 2006
    #1
    1. Advertising

  2. 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
     
    Szabolcs Borsanyi, Jul 29, 2006
    #2
    1. Advertising

  3. Artemio

    Michael Mair Guest

    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.
     
    Michael Mair, Jul 29, 2006
    #3
  4. Artemio

    Artemio Guest

    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.
     
    Artemio, Jul 30, 2006
    #4
  5. Artemio

    Artemio Guest

    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.
     
    Artemio, Jul 30, 2006
    #5
  6. Artemio

    Chris Torek Guest

    In article <>
    Artemio <> 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 (40°39.22'N, 111°50.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.
     
    Chris Torek, Jul 30, 2006
    #6
  7. Artemio

    Artemio Guest

    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.
     
    Artemio, Jul 30, 2006
    #7
  8. > 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
     
    Szabolcs Borsanyi, Jul 30, 2006
    #8
  9. Artemio

    Default User Guest

    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
     
    Default User, Jul 30, 2006
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Joe Foran
    Replies:
    0
    Views:
    481
    Joe Foran
    Aug 31, 2004
  2. Joe Rigley
    Replies:
    2
    Views:
    537
    Joe Rigley
    May 12, 2005
  3. Els

    Help desperately needed

    Els, Jul 19, 2004, in forum: HTML
    Replies:
    14
    Views:
    660
    Sam Hughes
    Jul 22, 2004
  4. Jeff
    Replies:
    1
    Views:
    420
  5. Uwe Mayer

    sscanf needed

    Uwe Mayer, Apr 17, 2005, in forum: Python
    Replies:
    5
    Views:
    544
    Lee Harr
    Apr 17, 2005
Loading...

Share This Page