ignoring whitespace with sscanf in C
I have a string such as "4 Tom Tim 6", and i am trying to scan those values with sscanf like this sscanf(string, "%d %s %d", &NUMBER1, NAME, &number2 )
is there any way to do this and deposit in NUMBER1开发者_C百科 the value 4, in NUMBER2 the value 6, and in NAME the value "Tom Tim"?
I tried but sscanf splits "Tom" and "Tim" because there is a whitespacew between them and thus it also returns a incorrect value for NUMBER2.
Update:
Let me be more specific. There will always be a number at the beginning and at the end of the my string, and a substring between those numbers, which could have any length and any quantity of whitespaces, and what im trying to get is that substring in a single variable, and the numbers in the beggining and the end.
You read it in as
sscanf(string, "%d %s %s %d", &NUMBER1, &NAME, &SECONDNAME, &NUMBER2);
then concatenate them
strcat(NAME," "); // Add space
strcat(NAME,SECONDNAME); // Add second name
Make sure that NAME has enough space to hold both the first and second name. You will also have to:
#include <string.h>
In order to come up with the solution (and tell whether it is even possible with sscanf
), you need to provide more information about the format of your string. It is not possible to derive anything conclusive from a single example you provided so far.
In your particular case one needs to know where the name ends and the next number begins. How do you define that in your case? Are we supposed to assume that the first decimal digit character means the end of the name and the beginning of the number2
? Or is it something more complicated? If the input string contains a "Tom16"
sequence, is the entire "Tom16"
supposed to be the name, or should we split it into "Tom"
and leave 16
for number2
?
Basically, your question, as stated, allows for no meaningful answer, only for random suggestions.
Update: Your description of the format of the string is still far from being complete, but I can suggest using the following format specifier in sscanf
sscanf(string, "%d %[^0123456789]%d", &number1, name, &number2)
This will work, assuming that the "numbers" you are referring to are composed of decimal digits only and assuming that name cannot contain any decimal digits. Also note that it will not include the leading space onto the name, but it will include the trailing space. If you don't want it you'll have to trim the trailing space from the name yourself.
In any case, parsing capabilities of sscanf
are rather limited. They are normally inadequate for solving problem like yours. What I have above is probably the best you can get out of sscanf
. If you need something even a little more elaborate, you'll have to parse your string manually, token by token, instead of trying to parse the whole thing in one shot with sscanf
.
No, not with sscanf()
.
You can do it 'easily' with fgets()
, and parsing the line character by character
/* basic incomplete version; no error checking; name ends with whitespace */
#include <ctype.h>
#include <stdio.h>
int num1, num2;
char name[250], line[8192], *p;
fgets(line, sizeof line, stdin);
num1 = num2 = 0;
p = line;
while (isdigit((unsigned char)*p) {num1 = num1*10 + *p - '0'; p++};
while (isspace((unsigned char)*p)) p++;
while (!isdigit((unsigned char)*p)) *name++ = *p++;
while (isdigit((unsigned char)*p) {num2 = num2*10 + *p - '0'; p++};
You can't do this work with the sscanf
function and a "central" string with an arbitrary number of spaces in it, since the whitespace is also your delimiter for the next field; if that %s
matched strings with whitespace, it would "eat" also the 6.
If it's only your "central" field that is "special" and you have only those three fields, you should read your string backwards to find the beginning of the third field, and transform it in number; then you replace the character before the 6 with a \0
, thus truncating the string before the third field.
Then you can use strtoul
to convert the first field and to determine where it ends (using its second parameter); considering the string that starts from there and goes to the end of the truncated string you get the second field.
@AndreyT is pretty much correct. I'm going to guess that the middle field should stop at any digit. If that's the case, then yes sscanf
can do the job:
sscanf(string, "%d %[^0-9] %d", &NUMBER1, NAME, &number2);
You really want to limit the amount that's read to the length of your buffer though:
char name[32];
sscanf(string, "%d %31[^0-9] %d", &number1, name, &number2);
I should add that technically this isn't portable as-is. To be entirely portable, you should use [^0123456789]
instead of [^0-9]
. Old versions of Borland compilers actually treated "0-9" as meaning the three characters '0', '-' and '9'. The standard permits this, though I don't know of any current compiler that takes its permission to be stupid.
You could :
sscanf(string, "%d %s %s %d", &NUMBER1, NAME1 , NAME2, &number2 );
strcat(NAME , NAME1);
strcat(NAME , " ");
strcat(NAME , NAME2);
But this would result in undefined behaviour, if NAME
is not big enough.
I can think of a couple of ways:
1) If you always know the size of the "Tom Tim" field, use the %c format with a length specifier:
int num1;
int num2;
char name[8];
sscanf(string, "%d %7c %d", &num1, name, &num2);
name[7] = '/0';
Note that NAME needs to be large enough to hold the characters read and that it won't be null terminated so that has to be done manually.
2) If you know there are always two fields, use two string specifiers and strncat() them together:
char name1[40];
char name2[20];
int num1;
int num2;
sscanf(string, "%d %s %s %d", &num1, name1, name2, &num2);
strncat(name1, name2, sizeof(name2)-1);
You could also parse the string using strtok_r(). I'll leave that as an exercise for the reader.
精彩评论