查看: 343|回复: 0
打印 上一主题 下一主题

C语言sscanf()函数格式化字符串用法

[复制链接]

45

主题

47

帖子

616

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
616
跳转到指定楼层
楼主
发表于 2019-2-15 09:39:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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的功能很类似于正则表达式, 但却没有正则表达式功能强大, 所以比较复杂的字符串处理, 建议使用正则表达式。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表