开发者

Sscanf with multiline string

I have a string with multiple lines and I want to use sscanf to match particular parts of it. It only seems to work however on matching data contained within the first line.

For example, If I have the string:

"age1: x \r\n age2: x"

And using sscanf:

sscanf(string, "age1: %d", &i); - this works

sscanf(string, "age2: %d", &a开发者_JAVA百科mp;j); - however this doesn't.

Any ideas?


As others have stated, sscanf doesn't remember how much data was read and advance the input data like scanf and fscanf do. Use the %n specifier to remember how much data was read, and advance the input yourself:

int bytesRead;
if(sscanf(string, "age 1: %d\n%n", &i, &bytesRead) == 1) &&
   sscanf(string + bytesRead, "age 2: %d", &j) == 1)
{
    // success
}
else
{
    // parsing failed
}

The %n specifier says "tell me how many bytes of input have been read up to this point, and store it in the next argument (which must be a pointer to an int)". By putting it at the end of the format string, we can figure out how much input was parsed. Also note that I added a newline after the %d so that we eat the whitespace after the first integer; otherwise when we attempted to read "age 2", it would see a newline next instead of the character a, and parsing would fail because that's not a match.


Using sscanf won't change the string like a stream, so in the second call of sscanf, it will begin to match age2 with age1, and since it does not match it will not read the value.

You could either make the second read after the content of read in the first, or you can also read it at once:

sscanf(string, "age1: %d \n\r age2: %d", &i, &j);


  1. Did you check the return status from sscanf()?
  2. What number did you expect the 'x' in the string to convert to?
  3. Since each call to sscanf() starts at the beginning, the 'Age2:' does not match 'Age1:' and therefore the conversion fails.

Note that any character in the format string that is not part of a conversion specifier has to be matched exactly. So, when the scan sees the 2 of 'Age2', it finds the 1 of 'Age1' in the string and the scan fails with a mismatch at that point. The exception is that white space is matched by any sequence of white space - see the code below.

Example code:

#include <stdio.h>

int main(void)
{
    const char string[] = "Age1: 3\r\nAge2: 5\r\n";
    const char *scan[] = { "Age1: %d", "Age2: %d", "Age1: %d Age2: %d" };
    int age1, age2;
    int rc;

    if ((rc = sscanf(string, scan[0], &age1)) != 1)
        printf("scan failed on '%s'\n", scan[0]);
    else
        printf("scan passed on '%s' - age %d\n", scan[0], age1);

    if ((rc = sscanf(string, scan[1], &age2)) != 1)
        printf("scan failed on '%s'\n", scan[1]);
    else
        printf("scan passed on '%s' - age %d\n", scan[1], age2);

    if ((rc = sscanf(string, scan[2], &age1, &age2)) != 2)
        printf("scan failed on '%s'\n", scan[2]);
    else
        printf("scan passed on '%s' - age1 %d, age2 %d\n", scan[2], age1, age2);

    return 0;
}

Example output

scan passed on 'Age1: %d' - age 3
scan failed on 'Age2: %d'
scan passed on 'Age1: %d Age2: %d' - age1 3, age2 5


The string has no way of remembering where the sscanf was after finishing reading the first line. (If you want that, you may want to look at the return value and remember it yourself.)

But you can just do it in one call:

sscanf(string, "age1: %d age2: %d", &i, &j);


if you are limited to c (ie can't use std::getline) then the easiest way is to read the data a character at a time and parse it yourself.

You can use atoi and atof to convert any numbers

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜