My aim is to extract the value and a key separated by an =
. My initial idea was to use something like %s=%s
, but unfortunately it doesn't work.
So I have a file:
A=1
B=2
So I open the file:
char *key;
char *value;
FILE* file = fopen("./file", "r");
do {
fscanf(file, "%[^'=']=%[^'\n']\n", key, value);
printf("key:%s value:%s\n", key, value);
} while(!feof(file));
However both key and value return:
key:1 value:1
key:2 value:2
Any idea why my expression is not matching?.
key
and value
variables must be allocated, eg
char key[100];
char value[1000];
Then use them.
char key[16];//char *key;//not point to memory for store.
char value[16];
FILE *file = fopen("./file", "r");
while(2==fscanf(file, " %[^=]=%[^\n]", key, value)){
printf ("key:%s value:%s\n", key, value);
}
Your pointers are uninitialized. Reading them is undefined in C. You can use arrays (if you know the maximal lengths at compile-time) or allocate memory with malloc
.
Read the *scanf
documentation carefully, these functions are a little tricky.
"%s=%s"
cannot match, %s
consumes all =
signs so the following =
is always a matching failure (the next character after %s
is always a whitespace or EOF).
When reading strings, always use a maximum field width (in some cases, it can be omitted safely, but only for sscanf
). Unfortunately, you have to hard-code that value (or build up the format string at run-time, but I wouldn't advise you to do so).
I'm not sure what the '
in the scan sets are supposed to do, %[^'=']
is equivalent to %[^'=]
and matches everything but '
and =
. You've probably meant %[^=]
.
Every white-space character in the format string (outside a scan set) is treated equally as "skip any white-space", that is, a space ( ) is the same as a newline. The whole format string is equivalent to
"%[^'=]=%[^'\n] " // Note the space at the end
To match a literal newline, you need to use a scanset (with a length).
Always check the return value of *scanf
(also for fopen
and any other function which can fail).
char key[64]; // Or whatever is appropriate for you,
char value[64]; // remember the 0-terminator needs one byte
FILE *file = fopen("./file", "r");
if(!file) {
perror("./file");
exit(1);
}
for(;;) {
int e = fscanf(file, "%63[^=]=%63[^\n]%1[\n]", key, value, (char[2]){ 0 });
if(e == -1) {
if(ferror(file)) {
perror("reading from ./file");
// handle read error
} else { // EOF reached on first character of line
break;
}
} else if(e < 3) {
// handle invalid input
} else {
printf("key:%s value:%s\n", key, value);
}
}
Alternatively, you could use assignment-suppression for the last newline as in "%63[^=]=%63[^\\n]%*1[\\n]"
and omit the last argument to fscanf
. By doing so, you can no longer detect if the last line ended in a newline.
My initial idea was to use something like
%s=%s
, but unfortunately it doesn't work.
Thats simply because *scanf
does not respect non-whitespace delimiters as you suspected. Furthermore, it does not support real regular expressions. Only a certain simple type of character classes [..]
are supported.
To your problem:
key
and value
have to be allocated static or dynamic, the rest can be simplified and written without fscanf
(your input is obviously line-oriented), which might get you into trouble at some point :
...
FILE* fh = fopen("file", "r");
char buffer[1024]; /* line buffer for reading file if file is line-oriented */
while( fgets(buffer, sizeof(buffer), fh) ) {
char key[256], val[256];
sscanf(buffer, "%[^=]=%[^\n]", key, val);
printf("key:%s val:%s\n", key, val);
}
fclose(fh);
...
Edit the length of the scan buffers ( key[256]
, val[256]
) depending on your input.
// sample working code
#include<stdio.h>
#include<stdlib.h>
int main(void) {
FILE* file = fopen("./file", "r");
if(NULL == file) {
printf("Failed to open file\n");
return EXIT_FAILURE;
}
do {
char key[256];
char value[256];
fscanf(file, "%[^'=']=%[^'\n']\n", key, value);
printf("key:%s value:%s\n", key, value);
}while(!feof(file));
fclose(file);
return EXIT_SUCCESS;
} // End of main()
Sample Output:
key:A value:1
key:B value:2
key:C value:3
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.