0

For a project I'm trying to read an int and a string from a string. Here the only problem is sscanf appears to break reading an %s when it sees a space and some special character. I want to print only String which is present inside special character. Is there anyway to get around this limitation? Here is an example of what I'm trying to do:

Similar to this link with little change

#include<stdio.h>
#include<stdlib.h>

int main(int argc, char** argv) {
    int age;
    char* buffer;
    buffer = malloc(200 * sizeof(char));
    sscanf("19 cool kid >>> ram <<<", "%d %[^\t\n] >>> %*s <<<", &age, buffer);

    printf("%s is %d years old\n", buffer, age);
    return 0;
}

What it prints is: "cool kid >>> ram <<< is 19 years old" where I need "ram is 19 years old". Is there any work around?

Note: some time "cool kid" string come "coolkid" like this also.

Community
  • 1
  • 1
Android learner
  • 1,871
  • 4
  • 24
  • 36
  • Well, you could try taking the '19' and two instances of `>>>` and `<<<` out of the quoted string you're passing to `sscanf` to start. If you put them into the string, they're going to be there when you print it back out. – Ken White Aug 26 '15 at 03:03
  • Do you _have_ to use `sscanf()`? a bit extra effort with `strtok()` will give you lot more flexibility, IMHO. – Sourav Ghosh Aug 26 '15 at 03:37
  • when calling malloc() 1) the expression: 'sizeof(char)' is defined as 1 and has no effect on the value passed to malloc.. to declutter the code remove that useless expression. 2) Always check (!=NULL) the returned value from malloc() to assure the operation was successful – user3629249 Aug 28 '15 at 07:01
  • this: '%[^\t\n]' is incorrect as there is no tab and no newline in the source string. – user3629249 Aug 28 '15 at 07:05

3 Answers3

2

You had it, you just had your discard in the wrong place (along with a slight capitalization issue):

#include <stdio.h>
#include <stdlib.h>

int main (void) {

    int age;
    char* buffer;
    if (!(buffer = malloc(200 * sizeof *buffer))) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }
    sscanf("19 cool kid >>> ram <<<", "%d %*[^>] >>> %s <<<", &age, buffer);

    printf("%s is %d years old\n", buffer, age);

    free (buffer);

    return 0;
}

Output

$ ./bin/sscanf_strange
ram is 19 years old
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
2

Could use sscanf(input, "%d%*[^>]>>>%199s", &age, buffer);. Anything after the %s is irrelevant in scanning for age and buffer. Not checking if all scanned can lead to trouble.

Suggest checking that the entire line parsed as expected. The simple solution is to use " %n" at the end. This saves the count of char scanned if scanning gets that far.

const char *input =  "19 cool kid >>> ram <<<";
int n = 0;
sscanf(input, "%d%[^>]>>>%*199s <<< %n", &age, buffer, &n);
if (n == 0 || input[n]) {
  puts("Bad Input");
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

You need to look for things that aren't a >, and you need to suppress assignment on the correct bits:

sscanf("19 cool kid >>> ram <<<", "%d %*[^>] >>> %199s <<<", &age, buffer);

The length quoted in the format is one less than the number of characters available; it doesn't count the terminal null byte, in other words.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • The original input had a single sequence of `>>>` characters before the bit you're interested in. The 'scan set' `%*[^>]` contains an 'assignment suppression' `*`, and then a negated (`^`) set of characters, `>`. This looks for one or more characters that is not a `>`. In context, that's after the `19`, so it matches the string `" cool kid "`. If you need to match the word `ram` in `"19 cool kid >>> >>> ram <<<"`, then you need to think much harder. What other variations in the input are possible? How do you spot the part that's to be matched? Is `"19 cool >>> ewe >>> ram <<<"` valid? Etc. – Jonathan Leffler Aug 28 '15 at 06:00