原文:https://www.etdev.net/thread-107-1-1.html
1. 概述
sscanf()为C语言标准库函数,用于从指定字符串中读入与指定格式相符的数据。函数原型声明在stdio.h头文件中:int sscanf(const char *str, const char *format, ...);
该函数根据参数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为必选,所有格式符必须以%开头。
2. 参数及格式符的含义
int sscanf(const char *str, const char *format, ...)
str -- 这是 C 字符串,是函数检索数据的源。
format -- 这是 C 字符串,包含了以下各项中的一个或多个:空格字符、非空格字符 和 format 说明符。
format 说明符形式为 [=%[width][modifiers]type=],具体讲解如下:
参数 |
描述 |
* | 这是一个可选的星号,表示数据是从流 stream 中读取的,但是可以被忽视,即它不存储在对应的参数中。 |
width | 这指定了在当前读取操作中读取的最大字符数。 |
modifiers | 为对应的附加参数所指向的数据指定一个不同于整型(针对 d、i 和 n)、无符号整型(针对 o、u 和 x)或浮点型(针对 e、f 和 g)的大小: h :短整型(针对 d、i 和 n),或无符号短整型(针对 o、u 和 x) l :长整型(针对 d、i 和 n),或无符号长整型(针对 o、u 和 x),或双精度型(针对 e、f 和 g) L :长双精度型(针对 e、f 和 g) |
type | 一个字符,指定了要被读取的数据类型以及数据读取方式。具体参见下一个表格。 |
1) 赋值抑制符 '*' 表明按照随后的转换符指示来读取输入,但将其丢弃不予赋值(“跳过”)。抑制符无需相应的指针可变参数,该转换也不计入函数返回的成功赋值次数。%*[width] [{h | l | L}]type 表示满足该条件的字符被过滤掉,不会向目标参数中赋值。
2) width表示最大读取宽度。当读入字符数超过该值,或遇到不匹配的字符时,停止读取。多数转换丢弃起始的空白字符。这些被丢弃的字符及转换结果添加的空结束符('\0')均不计入最大读取宽度。
3) {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类型存储。
两种特殊的格式符
1) []:字符集合。[]表示指定的字符集合匹配非空的字符序列;^则表示过滤。该操作不会跳过空白字符(空格、制表或换行符),因此可用于目标字符串不以空白字符分隔时。[]内可有一到多个非^字符(含连字符'-'),且无顺序要求。%[a-z]表示匹配a到z之间的任意字符,%[aB-]匹配a、B、-中的任一字符;%[^a]则匹配非a的任意字符,即获取第一个a之前的(不为a的)所有字符。^可作用于多个条件,如^a-z=表示^a-z且^=(既非小写字母亦非等号)。空字符集%[]和%[^]会导致不可预知的结果。
使用[]时接收输入的参数必须是有足够存储空间的char、signed char或unsigned char数组。[]也是转换符,故%[]后无s。
%[^]的含义和用法与正则表达式相同,故sscanf函数某种程度上提供了简单的正则表达式功能。
2) n:至此已读入值(未必赋值)的等价字符数,该数目必须以int类型存储。如"10,22"经过"%d%*[^0-9]%n"格式转换后,%n对应的参数值为3(虽然','未参与赋值)。
'n'并非转换符,尽管它可用'*'抑制。C标准声称,执行%n指令并不增加函数返回的赋值次数;但其勘误表中的描述与之矛盾。建议不要假设%n对返回值的影响。
sscanf 类型说明符:
类型 |
合格的输入 |
参数的类型 |
c | 单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符。 | char * |
d | 十进制整数:数字前面的 + 或 - 号是可选的。 | int * |
e,E,f,g,G | 浮点数:包含了一个小数点、一个可选的前置符号 + 或 -、一个可选的后置字符 e 或 E,以及一个十进制数字。两个有效的实例 -732.103 和 7.12e4 | float * |
o | 八进制整数。 | int * |
s | 字符串。这将读取连续字符,直到遇到一个空格字符(空格字符可以是空白、换行和制表符)。 | char * |
u | 无符号的十进制整数。 | unsigned int * |
x,X | 十六进制整数。 | int * |
附加参数 -- 这个函数接受一系列的指针作为附加参数,每一个指针都指向一个对象,对象类型由 format 字符串中相应的 % 标签指定,参数与 % 标签的顺序相同。
针对检索数据的 format 字符串中的每个 format 说明符,应指定一个附加参数。如果您想要把 sscanf 操作的结果存储在一个普通的变量中,您应该在标识符前放置引用运算符 &,例如:
int n;
sscanf (str,"%d",&n);
3. 返回值
如果成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF。
4. 实例用法
1) 常见用法。
char buf[512] ;
sscanf("123456 ", "%s", buf);
printf("%s\n", buf);
结果为:123456
2) 取指定长度的字符串。下例中,取最大长度为4字节的字符串。
sscanf("123456 ", "%4s", buf);
printf("%s\n", buf);
结果为:1234
3) 取到指定字符为止的字符串。下例中,取遇到空格为止的字符串。
sscanf("123456 abcdedf", "%[^ ]", buf);
printf("%s\n", buf);
结果为:123456
4) 取仅包含指定字符集的字符串。下例中,取仅包含1到9和小写字母的字符串。
sscanf("123456abcdedfBCDEF", "%[1-9a-z]", buf);
printf("%s\n", buf);
结果为:123456abcdedf
5) 取到指定字符集为止的字符串。下例中,取遇到大写字母为止的字符串。
sscanf("123456abcdedfBCDEF", "%[^A-Z]", buf);
printf("%s\n", buf);
结果为:123456abcdedf
6) 给定一个字符串abc/etdev@123,获取 / 和 @ 之间的字符串,先将 "abc/"过滤掉,再将非'@'的一串内容送到buf中
sscanf("abc/etdev@123", "%*[^/]/%[^@]", buf);
printf("%s\n", buf);
结果为:etdev
7) 给定一个字符串“hello, world”,仅保留world。(注意:“,”之后有一空格)
sscanf(“hello, world”, "%*s%s", buf);
printf("%s\n", buf);
结果为:world
%*s表示第一个匹配到的%s被过滤掉,即hello被过滤了,如果没有空格则结果为NULL。
8) 解析时间字符串如“YYYY/MM/DD,hh:mm:ss±zz”
char time[25] = “2019/01/01,12:30:10+00”;
int year, month, day, hour, minute, second;
sscanf(time, "%d/%d/%d,%d:%d:%d[^+-]", &year, &month, &day, &hour, &minute, &second);
//year=2019, month=1, day=1, hour=12, minute=30, second=10
printf("date time: %d-%02d-%02d %02d:%02d:%02d\r\n", year, month, day, hour, minute, second);
结果为:2019-01-01 12:30:10
sscanf的功能很类似于正则表达式, 但却没有正则表达式功能强大, 所以比较复杂的字符串处理, 建议使用正则表达式。