C-Language: How to get number from string via sscanf?

14,040

Solution 1

A combination of digit filtering and sscanf() should work.

int GetNumber(const char *str) {
  while (!(*str >= '0' && *str <= '9') && (*str != '-') && (*str != '+')) str++;
  int number;
  if (sscanf(str, "%d", &number) == 1) {
    return number;
  }
  // No int found
  return -1; 
}

Additional work needed for numbers that overflow.

A slower, but pedantic method follows

int GetNumber2(const char *str) {
  while (*str) {
    int number;
    if (sscanf(str, "%d", &number) == 1) {
      return number;
    }
    str++;
  } 
  // No int found
  return -1; 
}

Solution 2

scanf tries to match a pattern.... so if you knew the string was "He is 16 years old." where 16 was an integer number you wished to decode.

( I think your input string implies your format is somewhat free form. I'm assuming its predictable. )

{
char* inputstr = "He is 16 years old.";
int answer = 0;
int params = sscanf (inputstr, "He is %d years old.", &answer);
if (params==1)
    printf ("it worked %d",answer);
else
    printf ("It failed");
}

Solution 3

For starters, you should know that the strtok function is pretty ancient as well. It's in the C89 standard, but probably existed in many implementations before that (for example in 4.3BSD which was released in 1986). In fact, the sscanf function is probably newer than the strtok function.

But if you have such an ancient compiler that, and actually don't have the strtok function, and your input string doesn't follow the exact format you have in the question, but can be more free-form (and so can't really use the pattern-matching functionality of sscanf) then you have to parse the string manually.

This manual parsing can actually be quite simple, just loop over the string until you find a digit, then collect all consecutive digits while constructing the number. Once you get a non-digit character, you have your number. Of course, this will only get the first number in the string.

Solution 4

#include <stdio.h>

int main() {
    char * string = "He is 16 years old.";
    int age;
    if(sscanf(string, "%*[^0123456789]%d", &age)==1)
        printf("%d\n", age);
    else
        printf("not found\n");
    return 0;
}
Share:
14,040
Lively
Author by

Lively

hi

Updated on June 20, 2022

Comments

  • Lively
    Lively almost 2 years

    Recently I have need to extract a number from a string, but on really old C with means functions like strtok are not supported. I would prefer sscanf, but i can't understand it. Note that the integer is in random place (user-defined).

    In general thats what i want to happan as an example:

    Input:
    char * string = "He is 16 years old.";
    
    Output:
    16
    
  • Utkan Gezer
    Utkan Gezer about 10 years
    With sscanf this is as far as you could get Lively (OP). If you are to acquire some other non-standard input, anything else than "He is x years old.", sscanf won't do it.
  • Lively
    Lively about 10 years
    The string given is like example. Basically the user will just write random string with integer somewhere in it.. And the function has to output those integers. Is it even possible.. i just saw similar questions with sscanf as an answer, but not explanation how sscanf could be used.
  • Lively
    Lively about 10 years
    The compiler is even more then ancient.. strtok is not supported and even God do not know why. You mean convert the string in array and set compare if the first char is 0-10 then return it.. if not skip to the next?
  • Some programmer dude
    Some programmer dude about 10 years
    @Lively Oh my, I feel really sorry for you then! But yeah, that's the gist of it.
  • Lively
    Lively about 10 years
    Well hehe @Joachim i gotta get used doing this. Seems i will create a compare input-output function by myself. Thanks.
  • Johnny
    Johnny about 10 years
    Usually input strings conform to some agreed syntax. If it is totally free form then I would write a routine to split the input string between white space into an array of smaller strings. Then step through the array calling scanf on each. The Params value returns how many %d in out example decoded to a int (a maximum of one) in our example.
  • Lively
    Lively about 10 years
    Actually i've been trying proceed and finally made str to int function: int strtoint(char source[]) { int multiplier = 1; int i, result; for (i=strlen(source)-1; i>=0; i--) { if(source[i] >= '0' && source[i] <= '9') { result = result + ((source[i]-'0') * multiplier); multiplier *= 10; } } return result; }
  • chux - Reinstate Monica
    chux - Reinstate Monica about 10 years
    @Lively Could go in the forward direction. { size_t i; int result = 0; for (i=0; source[i]; i++) { if(source[i] >= '0' && source[i] <= '9') { result = result*10 + source[i] - '0'; }
  • Lively
    Lively about 10 years
    Thanks. I fixed this part already :) Also made strtok function by myself. I don't know if it would be useful if i post it. OFFTOPIC: if i had 2 more reputation i could answer my posts..
  • chux - Reinstate Monica
    chux - Reinstate Monica almost 4 years
    Fails corner case when string begins with am int like `"123abc".
  • Jason C
    Jason C over 3 years
    You may with to use while (!isdigit(*str)) { ... } as the condition instead. It's in <cctype> (cplusplus.com/reference/cctype/isdigit).
  • chux - Reinstate Monica
    chux - Reinstate Monica over 3 years
    @JasonC isdigit(*str) is UB when *str < 0. (*str >= '0' && *str <= '9') does not have that problem. An alternative is to use isdigit((unsigned char) *str) which handles most other cases.
  • Jason C
    Jason C over 3 years
    Good point thanks. And static_cast<unsigned char> if you're feeling even more official. Further, on that note, character literals evaluate to their value in the execution charset, which isn't specifically tied to ASCII, and so '1' technically isn't guaranteed to be >= '0' and <= '9', whereas isdigit(static_cast<unsigned char>(*str)) covers it.
  • Jason C
    Jason C over 3 years
    (Although the '0' + value's scattered all over the universe would scream if that ever weren't the case.)
  • chux - Reinstate Monica
    chux - Reinstate Monica over 3 years
    @JasonC C specifies '0' through '9' as sequential, so (*str >= '0' && *str <= '9') is good, ASCII or not as is '0' + value. static_cast<unsigned char>(*str) is a compiler error in C as this post is tagged. I suspect you are thinking of some other language.
  • chux - Reinstate Monica
    chux - Reinstate Monica over 3 years
    @JasonC Ref: "In both the source and execution basic character sets, the value of each character after 0 in the above list of decimal digits shall be one greater than the value of the previous." C17dr § 5.2.1 3
  • Jason C
    Jason C over 3 years
    Oh. Hey, thanks on all points. I have been awake for a very, very long time. I hope I don't add confusion for any readers. I'm going to close the browser before I make any messes anywhere else.