sscanf

Last time I blogged about how to use sprintf to format output, especially with numbers, into strings. This time it is sscanf, the reverse, how to extract information, such as numbers from a formatted strings.

A lot of situations call for such a process. Say you want to command your robot to move its arm by telling it to a certain angle on a certain motor. Also you may want to set the time on your arduino’s on board real time clock, or want arduino to play an MP3 clip with a sound shield out of several clips. Maybe you want to control fan speeds of your HVAC system over the internet.

Back to the robot problem, say the arm has 3 motors, rotation around a vertical axis from the base, rotation of the arm up and down, and rotation of the grabber along the arm. A natural way is to pass such a command as “MA 150 MB 30 MC 25” to command the three motors to rotate to these angles, MA to 150, MB to 30, MC to 25. Using a string, you can either type up the command in arduino IDE’s serial monitor, or have a program on your PC generate this string to control the robotic arm. The following is pseudo code to process this:

  • Define 3 variables to store extracted numbers
  • Extract each number according to a predefined format
  • A final check to make sure extraction is successful

The more actual pseudo code:

#define expected_number_of_extracted_values 3

char input_string[]=”MA 150 MB 30 MC 25″;

int A_val, B_val, C_val;

int result;

result=sscanf(input_string, format description, list of variables to store the extracted numbers);

if (result!=expected_number_of_extracted_values) complain to user.

So let’s look at the format description. This is very similar to sprintf. The expected string has a character or string followed by space then a number, then repeat two more times for 3 parameters. This is described by the following formatting string: “%s %d %s %d %s %d”. The “%s” is a space holder for a string. The MA, MB, an MC are strings. The “%d” is a space holder for an integer. So 150, 30, and 25. So it reads “string integer string integer string integer”.

Next, you decide to not care about the actual string being MA or MB or MC because you always type them in that order. We will make a less strict assumption later. This strict requirement makes the first number always for motor MA, the second number for motor MB etc. Actually you don’t even need MA MB or MC in the string if you so decide the order of the numbers. But sometimes the string is not generated by you so there are junks and we need to extract number around them.

According to what we discussed in sprintf, the format string needs to have corresponding variables, so the actual sscanf will look like:

sscanf(input_string, “%s %d %s %d %s %d”, string1, A_val, string2, B_val, string3, C_val);

Since you don’t care about extracting the strings “MA”, “MB”, and “MC”, you can use this format string:

“%*s %d %*s %d %*s %d”

Notice the stars in front of the s. Any format term with a star makes the function extract the content and then discard it. This is different from omitting “%s” in the format string and making it “%d %d %d”. If you omit the “%s” in the format string, sscanf will try to match the first thing it sees with an integer and will fail since the first thing it sees is “MA”, which is not a number. It returns failure.

So to summarize, you need the following actual command:

sscanf(input_string,”%*s %d %*s %d %*s %d”, &A_val, &B_val, &B_val);

The ampersand or ‘&’ extracts address of the variables instead of values of them. With address, sscanf can return extracted values to variables.

Actual code:

#define expected_number_of_extracted values 3

char input_string[]=”MA 150 MB 30 MC 25″;

int A_val, B_val, C_val;

int result;

result=sscanf(input_string,”%*s %d %*s %d %*s %d”, &A_val, &B_val, &C_val);

if (result!=expected_number_of_extracted_values) fail();

For more detailed information on sscanf, read this page:

http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/

4 Responses to sscanf

  1. Jesper Hauge says:

    Hi Dr. Liu

    I would like to ask you a few questions about buying the PHI-2 shield from you. If you have time, I would really appreciate it if you could send me a mail when you got time 🙂

    Cheers,

    Jesper

  2. Jim Bob says:

    Thanks for the concise explanation.

    sscan() seems to require a space between format descriptors. The following test results in strange output …

    #include

    char input_string[]=”MA 150 MB 30 MC55″;

    int val=-1, result, int A_val=-1, B_val=-1, C_val=-1;

    void main()
    {
    result=sscanf(input_string,”%*s %d %*s %d %s %d”, &A_val, &B_val, &C_val);
    printf(“result = %d\n\n”,result);
    printf(“%d %d %d \n\n”, A_val, B_val, C_val);

    }

    PS, when you wrote ,
    result=sscanf(input_string,”%*s %d %*s %d %*s %d”, &A_val, &B_val, &B_val);

    I think you meant,
    result=sscanf(input_string,”%*s %d %*s %d %*s %d”, &A_val, &B_val, &C_val);

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: