Your update seems to be a good answer. I was going to suggest strchr
to find the location of the first quote char, after using sscanf
to get i1
thru i4
. Side note, you should always check the return value from sscanf
to make sure that the conversions worked. This is even more important with your suggested answer, since n
will be left uninitialized if the first four conversions aren't successful.
reading the remainder of a string with sscanf
سؤال
I'm trying to read a string which consists of a set of numbers followed by a string, wrapped with some other basic text.
In other words, the format of the line is something like this:
Stuff<5,10,-5,8,"Test string here.">
Naively, I tried:
sscanf(str,"Stuff<%d,%d,%d,%d,\"%s\">",&i1,&i2,&i3,&i4,str2);
But after some research I discovered %s
is supposed to stop parsing when it gets to a whitespace character. I found this question, but none of the answers addresses the problem I have: the string could contain any character in it, including newline characters and properly escaped quotes. The latter is not a problem, if I can just get sscanf to put everything after the first quote in the pre-allocated buffer I provide, I can strip the end off myself.
But how do I do this? I can't use %[]
because it requires something in it to terminate the string, and the only thing I want to terminate it is the null terminator. So I thought, "Hey, I'll just use the null terminator!" But %[\0]
made the compiler grumpy:
warning: no closing ‘]’ for ‘%[’ format
warning: embedded ‘\0’ in format
warning: no closing ‘]’ for ‘%[’ format
warning: embedded ‘\0’ in format
Using something like %*c
won't work either, because I don't know exactly how many characters need to be taken. I tried passing strlen(str)
since it will be less than that, but sscanf
returns 4 and nothing is put into str2
, suggesting that perhaps because the length was too long it gave up and didn't bother.
Update: I guess I could do something like:
sscanf(str,"Stuff<%d,%d,%d,%d,\"%n",&i1,&i2,&i3,&i4,&n);
str2 = str+n;
المحلول
نصائح أخرى
Scan for '\"'
, then for everything not '\"'
, then '\"'
again.
Be sure to check sscanf()
result and limit how long the test string may be.
char test_string[100];
int n = 0;
if (sscanf(str, "Stuff<%d,%d,%d,%d, \"%99[^\"]\"> %n",
&i1, &i2, &i3, &i4, test_string, &n) == 5 && str[n] == '\0') Good();
Your attempt using "...%[\0]..."
, from sscanf()
point-of-view, is "...%["
.
Everything in the format from "\0"
on is ignored.
Using the int n = 0
, appending " %n"
to the format string, appending &n
to the parameters and checking str[n] == '\0'
is a neat trick with sscanf()
to insure the entire line parsed correctly. Note: "%n"
does not add to sscanf()
result.
This is not the only way to achieve what you want to achieve, but probably the neatest way to do it: You'll need to use the scansets. I won't tell you the solution directly with this answer, I'll explain how to use scansets as far as I know them, and you'll hopefully be able to do it yourself.
Scansets %[...]
are like %s
when it comes to assignment, they interpret values as characters and store them into character arrays. %s
is whitespace-terminated, %[...]
is the flexible version of that.
There are two ways of using the scanset, first one being without a preceding caret ^
, second one being with a preceding caret ^
.
When you use scanset without the preceding caret ^
, the characters you put inside the brackets will be the only ones that will be read, stored and then left behind. As soon as scanf
encounters a non-matching character, that %[...]
will be over. For example:
// input: asdasdasdwasdasd
char s[100] = { 0 };
scanf( "%[das]", s );
printf( "%s", s );
// output: asdasdasd
When you use scanset with the preceding caret ^
, the search is inversed. It reads, stores and leaves behind every character until it reaches any one of the characters that you've put down after the preceding caret ^
. Example:
// input: abcdefgh^kekQ
char s[100] = { 0 };
scanf( "%[^Q^]", s );
printf( "%s", s );
// output: abcdefgh
Beware, remaining characters is still to be read inside the stream, the file pointer won't get beyond the character which caused termination. I.e. for the first one, getchar( );
would give a 'w'
, and for the second one it would give a '^'
.
I hope this will be enough. If you still cannot find your way out, ask away, I can give you a solution.