sscanf的字符串格式化用法
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为必选,所有格式符必须以%开头。
以下简要说明各格式符的含义:
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类型存储。
4) type 为类型转换符,如%s、%d。
此外,还有两种特殊的格式符:
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函数常见的格式化用法:
原字符串 |
格式化字符串 |
结果字符串 |
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-f] |
12345h |
12345helloWORLD |
%*[1-9]%[a-z] |
hello |
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 |
Name = Yuan |
%*[^=]=%*[ \t]%s |
Yuan |
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 |
串1:wxy;串2:zte.com.cn |
IpAddr=10.46.44.40 |
%[^=]=%s |
串1:IpAddr;串2:10.46.44.40 |
1hello234world5 |
1%[^2]234%[^5] |
串1:hello;串2:world |
Michael/nWang |
%[^/n]%*c%*c%s |
串1:Michael;串2:Wang |
Michael\nWang |
%[^\n]%*c%s |
串1:Michael;串2:Wang |
13:10:29-13:11:08 |
%[0-9,:] - %[0-9,:] |
串1:13:10:29;串2:13:11:08 |
10.46.44.40 |
%d.%d.%d.%d |
串1:10;串2:46;串3: 44;串4: 40 |
此外,还有如下几种用法:
【例1】读入一行字符串
因字符串可能含空白字符,故不能直接使用%s;而gets函数存在溢出风险,不推荐使用。此时,可使用sscanf函数,格式化字符串设为"%[^\n]%*c"。%*c用于跳过换行符\n,以便再次读入下一行。
【例2】提取"Name = Yuan"中的"Name"
若行首有空白字符,可用"%*[ \t]%[^= \t]"格式串;
若不确定行首有无空白字符,可先跳过空白字符:
char szName[] = "Name = Yuan";
char szResBuf[] = {};
sscanf(szName+strspn(szName," \t"), "%[^= \t]", szResBuf);
【例3】分解URL
普通实现如下所示:
/*****************************************************************************
* 函数名称:OaSplitPwFarEndIpInfo
* 功能描述:将远端IP信息分解为目的IP地址和端口号
* 注意事项:远端IP信息应形如'udp://192.168.100.221:5000'
*****************************************************************************/
static FUNC_STATUS OaSplitPwFarEndIpInfo(INT8U *pucFarEndIpInfo, INT32U *dwDstUdpPort, INT8U *pucDstIpAddr)
{
FUNC_STATUS retCode = S_OK;
INT8U strUdpHead[] = "udp://";
INT8U ucUdpUrlLen = strlen(strUdpHead);
INT8U ucIndex = ; CHECK_TRIPLE_POINTER(pucFarEndIpInfo, dwDstUdpPort, pucDstIpAddr, S_NULL_POINTER); if(strncasecmp(pucFarEndIpInfo, strUdpHead, ucUdpUrlLen) != )
{
OmciLog(LOG_CES,"[%s]Cannot Parse FarEndIpInfo(%s)!\n\r", __FUNCTION__, pucFarEndIpInfo);
return S_ERROR;
} INT8U ucMaxUrlLen = ucUdpUrlLen + STR_IPV4_MAX_LEN; //避免未配置端口时陷入死循环(infinite loop)
for(ucIndex = ; (pucFarEndIpInfo[ucUdpUrlLen] != ':') && (ucUdpUrlLen < ucMaxUrlLen); ucIndex++)
{
pucDstIpAddr[ucIndex] = pucFarEndIpInfo[ucUdpUrlLen++];
}
pucDstIpAddr[ucIndex] = '\0'; *dwDstUdpPort = strtoul(&pucFarEndIpInfo[ucUdpUrlLen+], NULL, ); return retCode;
}
使用sscanf格式化则更为简单:
char szUrl[] = "udp://192.168.100.221:5000";
char szProt[] = {}, szIp[] = {};
unsigned int dwPort = ;
sscanf(szUrl, "%[^://]%*c%*c%*c%[^:]%*c%d", szProt, szIp, &dwPort);
printf("szProt=%s, szIp=%s, dwPort=%d\n", szProt, szIp, dwPort);
【例4】提取数字
char szDig[]="10,22m,Z86,,880;555:666.";
int dwIdx = , dwVal = , dwSize = ;
while( == sscanf(szDig+dwIdx, "%d%*[^0-9]%n", &dwVal, &dwSize))
{
dwIdx += dwSize;
printf("dwIdx=%d, dwSize=%d, dwVal=%d\n", dwIdx, dwSize, dwVal);
}
上述实现稍加改造,即可用于处理某种字符分隔的数字串。
综上,对于简单的字符串分析,采用sscanf函数处理比较简洁。若字符串比较复杂,则可借助相应的正则表达式库。需要注意,sscanf格式化的目的是“截取”,而正则表达式的目的是“匹配”,不能完全等同。
sscanf的字符串格式化用法的更多相关文章
- Python_字符串格式化
#冒泡排序 array = [1,2,3,6,5,4] for i in range(len(array)): for j in range(i): if array[j] > array[j ...
- Python中用format函数格式化字符串的用法
这篇文章主要介绍了Python中用format函数格式化字符串的用法,格式化字符串是Python学习当中的基础知识,本文主要针对Python2.7.x版本,需要的朋友可以参考下 自python2. ...
- Java字符串格式化String.format常用用法
常规的格式化 String类的format()方法用于创建格式化的字符串以及连接多个字符串对象.熟悉C语言的同学应该记得C语言的sprintf()方法,两者有类似之处.format()方法有两种重载形 ...
- Java 字符串格式化详解
Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...
- Python字符串格式化
一.使用格式化符来格式化字符串: Python支持的所有格式化符 格式化符 意义 'd' 返回要格式化对象的十进制表示,如果可以 'i' 返回要格式化对象的十进制表示,如果可以 'o' 返回要格式化对 ...
- python-学习笔记之-Day5 双层装饰器 字符串格式化 python模块 递归 生成器 迭代器 序列化
1.双层装饰器 #!/usr/bin/env python # -*- coding: utf-8 -*- # author:zml LOGIN_INFO = False IS_ADMIN = Fal ...
- Asp.net日期字符串格式化显示
我们经常会遇到对时间进行转换,达到不同的显示效果,默认格式为:2006-6-6 14:33:34 如果要换成成200606,06-2006,2006-6-6或更多的格式该怎么办呢?这里将要用到:Dat ...
- 字符串:格式化 - 零基础入门学习Python015
字符串:格式化 让编程改变世界 Change the world by program 字符串:格式化 上节课我们介绍了Python字符串的N多种奇葩方法的用法,但我们唯独漏了一个format()方法 ...
- C#字符串处理 及字符串格式化
本文来自:http://www.cnblogs.com/xuerongli/archive/2013/03/23/2976669.html string字符串是char的集合,而char是Unicod ...
随机推荐
- pkg-config命令的Makefile.am
举例:通过Makefile调用pkg-config命令. pkg-config - Return metainformation about installed libraries (为了使用lib库 ...
- CentOS7 命令笔记
网络 ifconfig已经过时,查看ip地址请使用ip addr或者ip link 服务 查看系统和硬件信息 cat /etc/os-release uname -r 显示正在使用的内核版本 dmid ...
- jstl 格式化
一:JSTL格式化标签又称为I18N标签库,主要用来编写国际化的WEB应用,使用此功能可以对一个特定的语言请求做出合适的处理.例如:中国内地用户将显示简体中文,台湾地区则显示繁体中文,使用I18N格式 ...
- Redis相关技巧
一. 内存占用过大,设置内存最大上限. vi /etc/redis.conf maxmemory 1g maxmemory-policy allkeys-lru (慎用) appendonly yes ...
- Swift 柯里化
前言 由于柯里化在业务层的应用较少,所以从 Swift 3.0 开始移除了柯里化的用法,但是 Swift 的很多底层特性是使用柯里化来表达的. 1.柯里化 1.1 柯里化简介 柯里化(Currying ...
- 2013-2015 Aaronyang的又一总结,牧童遥指纳尼村
我没有时间去唠叨自己的事,可是你们是我喜欢的人,ay很愿意写给你们分享:去年的万人阅读的总结链接:<没学历的IT人生没那么悲催,献给程序员们> 提前声明:本文不良反应:请自备垃圾桶,准备装 ...
- Fluent动网格【8】:网格节点运动案例
Fluent动网格中的DEFINE_GRID_MOTION宏允许用户定义网格节点的运动.本案例演示采用DEFINE_GRID_MOTION宏指定边界节点的运动. 案例动网格效果如图所示. 案例描述 本 ...
- Unity的Attribute(特性)还算多吧
属性 (Attribute) 使用 Unity 的C#语言 ,利用属性(Attribute)来类定义和变量定义或区分其他的变量,您可以设置一种特殊行为.* 1 例如,您添加[SerializeFiel ...
- linux每日命令(10):touch命令
linux的touch命令一般用来修改文件时间戳,或者新建一个不存在的文件. 一.命令格式: touch [参数]... 文件... 二.命令参数: 参数 描述 -a 或--time=atime或-- ...
- 浅谈.net中事务
.net中的事务 关键几点 概念:1:什么是事务 2:什么时候用事务 3:基本的语法 (1): 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit).事务通常 ...