标准库函数族
NAME
scanf, fscanf, sscanf, vscanf, vsscanf, vfscanf - input format conversion
SYNOPSIS
#include <stdio.h>
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
#include <stdarg.h>
int vscanf(const char *format, va_list ap);
int vsscanf(const char *str, const char *format, va_list ap);
int vfscanf(FILE *stream, const char *format, va_list ap);
- 该函数根据参数format(格式化字符串)来转换参数str指向的字符串,转换后的结果存于对应的可变参数内。其返回值为按照指定格式转换符成功读入且赋值的可变参数数目(若发生匹配错误而部分成功,该数目会小于指定的参数数目,甚至为0)。若首次成功转换或错误匹配发生前输入已结束(如str为空字符串),则返回EOF。发生读取错误时也返回EOF,且设置错误码errno(如format为空指针时返回EOF并设置errno为EINVAL)。可见,通过比较该函数的返回值与指定的可变参数数目,可判断格式转换是否成功。
format
可为一个或多个{%[*] [width] [{h | l | L}]type | ' ' | '\t' | '\n' | 非%符号}
格式转换符。集合中{a|b|c}
表示格式符a、b、c任选其一。以中括号括起来的格式符可选。%
与type
为必选,所有格式符必须以%开头。
- 赋值抑制符
'*'
表明按照随后的转换符指示来读取输入,但将其丢弃不予赋值(“跳过”)。抑制符无需相应的指针可变参数,该转换也不计入函数返回的成功赋值次数。%*[width] [{h | l | L}]type
表示满足该条件的字符被过滤掉,不会向目标参数中赋值
width
表示最大读取宽度。当读入字符数超过该值,或遇到不匹配的字符时,停止读取。多数转换丢弃起始的空白字符。这些被丢弃的字符及转换结果添加的空结束符('\0')均不计入最大读取宽度。
{h | l | L}
为类型修饰符。h指示输入的数字数值以short int或unsigned short int类型存储;hh指示输入以signed char或unsigned char类型存储。l(小写L)指示输入以long int、unsigned long int或double类型存储,若与%c或%s结合则指示输入以宽字符或宽字符串存储;ll等同L。L指示输入以long long类型存储。
type
为类型转换符,如%s、%d。
[]
:字符集合。[]表示指定的字符集合匹配非空的字符序列;^
则表示过滤。该操作不会跳过空白字符(空格、制表或换行符),因此可用于目标字符串不以空白字符分隔时。[]
内可有一到多个非^字符(含连字符'-'),且无顺序要求。%[a-z]
表示匹配a到z之间的任意字符,%[aB-]
匹配a、B、-中的任一字符;%[^a]
则匹配非a的任意字符,即获取第一个a之前的(不为a的)所有字符。^可作用于多个条件,如^a-z=表示^a-z且^=(既非小写字母亦非等号)。空字符集%[]
和%[^]
会导致不可预知的结果。
- 使用
[]
时接收输入的参数必须是有足够存储空间的char、signed char或unsigned char数组。[]
也是转换符,故%[]
后无s。
%[^]
的含义和用法与正则表达式相同,故sscanf函数某种程度上提供了简单的正则表达式功能。
格式化示例
原始字符转 |
格式化字符串 |
格式化结果 |
备注 |
helloworld |
%s |
helloworld |
|
hello, world |
%s |
hello, |
|
hello, world |
%4s |
hell |
|
hello, world |
%*s%s |
world |
若原字符串无空格则得到空串 |
hello, world |
%[^ ] |
hello, |
|
hello, world |
%[a-z] |
hello |
|
12345helloWORLD |
%[1-9a-z]或%[a-z1-9] |
12345hello |
|
12345helloWORLD |
%[^A-Z] |
12345hello |
|
12345helloWORLD |
%[^a-z] |
12345h |
|
12345helloWORLD |
%[a-z] |
(空串,需先过滤前面不需要的字符) |
|
12345helloWORLD= |
%[1-9]%[a-z]%[^a-z=] |
WORLD |
|
12345/hello@world |
%*[^/]/%[^@] |
hello |
|
IpAddr=10.46.44.40 |
%*[^=]=%s |
10.46.44.40 |
|
email:wxy@zte.com.cn; |
%*[^:]:%[^;] |
wxy@zte.com.cn |
|
email:wxy@zte.com.cn |
%*[^:]:%s |
wxy@zte.com.cn |
|
wxy@zte.com.cn |
%[^@]%*c%s |
wxy@zte.com.cn |
|
1hello234world5 |
1%[2]234%[5] |
串1:hello 串2:world |
|
Michael/nWang |
%[^/n]%c%c%s |
串1:Michael 串2:Wang |
|
Michael\nWang |
%[^\n]%c%c%s |
串1:Michael 串2:Wang |
|
13:10:29-13:11:08 |
%[0-9,:]-%[0-9,:] |
串1:13:10:29 串2:13:11:08 |
|
示例源码
#include <stdio.h>
#include <string.h>
#define SIZE 256
void test_format(const char* raw, const char* format, char* buf) {
sscanf(raw, format, buf);
printf("%-25s%-20s%-20s", raw, format, buf);
printf("\n");
memset(buf, 0, SIZE);
}
void test_format2(const char* raw, const char* format, char* buf1, char* buf2) {
sscanf(raw, format, buf1, buf2);
printf("%-25s%-20s%-20s%-20s", raw, format, buf1, buf2);
printf("\n");
memset(buf1, 0, SIZE);
memset(buf2, 0, SIZE);
}
int main(int argc, char* argv[]) {
char buf1[SIZE] = {0};
char buf2[SIZE] = {0};
test_format("helloworld", "%s", buf1);
test_format("hello, world", "%s", buf1);
test_format("hello, world", "%4s", buf1);
test_format("hello, world", "%*s%s", buf1);
test_format("hello, world", "%[^]", buf1);
test_format("hello, world", "%[a-z]", buf1);
test_format("12345helloWORLD", "%[1-9a-z]", buf1);
test_format("12345helloWORLD", "%[^A-Z]", buf1);
test_format("12345helloWORLD", "%[^a-z]", buf1);
test_format("12345helloWORLD", "%[a-z]", buf1);
test_format("12345/hello@world", "%*[^/]/%[^@]", buf1);
test_format("IpAddr=10.46.44.40", "%*[^=]=%s", buf1);
test_format("email:wxy@zte.com.cn;", "%*[^:]:%[^;]", buf1);
test_format("email:wxy@zte.com.cn", "%*[^:]:%s", buf1);
test_format2("wxy@zte.com.cn", "%[^@]%*c%s", buf1, buf2);
test_format2("IpAddr=10.46.44.40", "%[^=]=%s", buf1, buf2);
test_format2("1hello234world5", "1%[^2]234%[^5]", buf1, buf2);
test_format2("Michael/nWang", "%[^/n]%*c%*c%s",buf1, buf2);
test_format2("Michael\\nWang", "%[^\\n]%*c%*c%s", buf1, buf2);
test_format2("13:10:29-13:11:08", "%[0-9,:]-%[0-9,:]", buf1, buf2);
return 0;
}