sscanf,sprintf,snprintf和stringstream用法

sscanf,sprintf,snprintf和stringstream

1. sscanf

C 库函数,int sscanf(const char *str, const char *format, …) 从字符串读取格式化输入。如果成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF。和scanf的区别是scanf是以键盘作为输入源,sscanf是以字符串作为输入源。

  • str:这是c字符串,是函数检索数据的源
  • format:这是 C 字符串,包含了以下各项中的一个或多个:空格字符、非空格字符 和 format 说明符。format 说明符形式为[=%[*][width][modifiers]type=]
  • 附加参数:这个函数接受一系列的指针作为附加参数,每一个指针都指向一个对象,对象类型由 format 字符串中相应的 % 标签指定,参数与 % 标签的顺序相同。参数前面要加&。

format中,*是可选的,表示数据是从流 stream 中读取的,但是可以被忽视,跳过此数据不读入,即它不存储在对应的参数中;width表示读取的最大字符数,modifiers表示参数的size,通常h表示单字节size,I表示2字节 size,L表示4字节size(double例外),l64表示8字节size;type指定了要被读取的数据类型以及数据读取方式,可以是c(单个字符char*),d(十进制整数int*),eEfgG(如-732.103 和 7.12e4 float*),o(八进制整数),s(字符串),u(无符号十进制整数),xX(十六进制整数)。
同时支持集合操作:
%[a-z] 表示匹配a到z中任意字符,贪婪性(尽可能多的匹配)
%[aB’] 匹配a、B、'中一员,遇见非其中的字符就停止,贪婪性
%[^a] 匹配非集合a中的任意字符,遇到a中的字符就停止,贪婪性
%[1-9,a-z] 范围链接,表示同时取1-9数字和a-z小写字母

总的来说,这个函数将参数str的字符串根据参数format字符串来转换并格式化数据,转换后的结果存于对应的参数内,有以下几种功能:
(1)根据格式从字符串中提取数据。如从字符串中取出整数、浮点数和字符串等。
(2)取指定长度的字符串
(3)取到指定字符为止的字符串
(4)取仅包含指定字符集的字符串
(5)取到指定字符集为止的字符串
几个常用的例子:

int year, month, day, hour, minute, second;
sscanf("2013/02/13 14:55:34","%d/%d/%d %d:%d:%d",&year, &month, &day, &hour, &minute, &second);
printf("time=%d-%d-%d %d:%d:%d\n", year, month, day, hour, minute, second);
//time=2013-2-13 14:55:34

char buf[100];
sscanf("123456 ", "%4s", buf);
printf("%s\n", buf);
//1234

char str1[100]="abc def", str2[100], str3[100];
sscanf(str1,"%s%s",str2,str3);
printf("%s %s\n",str2,str3);
//abc def

char str[100];
sscanf("1234abcd","%*d%s",str);
printf("%s\n",str);
//abcd

char str[100];
sscanf("1234+abc","%[^+]",str);
printf("%s\n",str);
//1234

char str[100];
sscanf("123456abcdefBFRGTY7890","%[1-9a-z]",str);
printf("%s\n",str);
//123456abcdef

const char *s = "http://www.baidu.com:1234";
char protocol[32] = { 0 };
char host[128] = { 0 };
char port[8] = { 0 };
sscanf(s,"%[^:]://%[^:]:%[1-9]",protocol,host,port);
//解析网址

2. sprintf

C 库函数,int sprintf(char *str, const char *format, …) 发送格式化输出到 str 所指向的字符串。如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

  • str:这是指向一个字符数组的指针,该数组存储了 C 字符串
  • format:这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是%[flags][width][.precision][length]specifier
  • 附加参数:根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同

format中,specifier可以是c,d或I,eE(科学技术法,尾数或指数),f,gG(自动选择 %e 或 %f 中合适的表示法),o,s,u,x,X(大写16进制),p(指针地址),n(无输出),%(字符);flags可以是-(左对齐,默认是右对齐),+(强制在结果之前显示+ 或 -,默认情况下,只有负数前面会显示-),空格space(如果没有写入任何符号,则在该值前面插入一个空格),#(与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X,与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点,与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除),0(在指定填充 padding 的数字左边放置0,而不是空格);width表示要输出的字符的最小数目,.precision表示精度;length表示参数长度,可以是h(短整型),l(长整型)和L(长双精度型)

总的来说,sprintf作用是格式化字符串,有以下几种功能:
(1)将数字变量转换为字符串。
(2)得到整型变量的16进制和8进制字符串。
(3)连接多个字符串。
几个常用的例子:

char s[100];
int a=10;
sprintf(s,"%d.jpg",a);
printf("%s\n",s);
//"10.jpg
char buf[100];
sprintf(buf,"%8d%8d", 12,78995);  
puts(buf);
//      12   78995

char buf[100];
sprintf(buf, "%-8x", 4578);  
puts(buf); //11e2    左对齐输出
sprintf(buf, "%08x", 4578);  
puts(buf); //000011e2 左边补0输出

char buf1[]="I"; char buf2[]="you!";  
sprintf(buf, "%s love %s", buf1, buf2);  
puts(buf); 
//I love you! 

3. snprintf

snprintf函数是sprintf函数的更加安全版本,考虑到字符串的字节数,防止了字符串溢出。函数形式为:int snprintf(char *restrict buf, size_t n, const char * restrict format, …)。最多从源串中拷贝n-1个字符到目标串中,然后再在后面加一个0。
如果格式化后的字符串长度小于size,则将字符串全部拷贝至dest_str中,并在字符串结尾处加上‘\0’; 如果格式化后的字符串长度大于或等于size,则将字符串的(size-1)拷贝至dest_str中,然后在字符串结尾处加上’\0’。函数返回值是格式化字符串的长度。

char dest_str[1024];  
memset(dest_str,0,sizeof(dest_str));  
char *s1 = "Linux C程序设计";  
int size = strlen(s1);  
int year = 2017;  
int month = 9;  
int day = 8;  
snprintf(dest_str,sizeof(dest_str),"字符串:%s\n长度是:%d\n今天是:%d年%d月%d日\n",s1,size,year,month,day);
printf("%s",dest_str); 
//字符串:Linux C程序设计
//长度是:15
//今天是:2017年9月8日

4. stringstream

stringstream和iostream、fstream有类似的操作方式,要使用stringstream, 必须先#include <sstream>。 主要用来进行数据类型转换,由于 使用 string 对象来代替字符数组(snprintf方式),就避免缓冲区溢出的危险;而且,因为传入参数和目标对象的类型会被自动推导出来,所以不存在错误的格式化符的问题。简单说,相比c库的数据类型转换而言, 更加安全、自动和直接。
stringstream用法有以下几种:

  1. string->int
stringstream stream;
string result="1000";
int n=0;
stream<<result;
stream>>n;//n=1000
  1. int->string
stringstream stream;
string result;
int i = 1000;
stream << i; //将int输入流
stream >> result; //从stream中抽取前面插入的int值,result="1000"
  1. int->char*
stringstream stream;
char result[10] ;
stream << 1000; //向stream中插入1000
stream >> result; //抽取stream中的值到result,result="1000"
  1. 格式转换模版
//转换成字符串的模版
template<class T>
void to_string(string & result,const T& t)
{
	ostringstream oss;//创建一个流
	oss<<t;//把值传递入流中
	result=oss.str();//获取转换后的字符转并将其写入result
}
//main中
to_string(s1,10.5);//double到string
to_string(s2,123);//int到string
to_string(s3,true);//bool到string

//通用的转换模板,用于任意类型之间的转换
template<class out_type,class in_value>
out_type convert(const in_value & t)
{
	stringstream stream;
	stream<<t;//向流中传值
	out_type result;//这里存储转换结果
	stream>>result;//向result中写入值
	return result;
}
//main中
double d;
string salary;
string s=12.56;
d=convert<double>(s);//d等于12.56
salary=convert<string>(9000.0);//salary等于”9000”
  1. split字符串
string inputString("/home/fun/./../code/");
stringstream ss(inputString);
string tmp;
while(getline(ss,tmp,'/'))
{
   if(tmp.empty())   continue;
   cout<<tmp<<endl;  //输出home fun . .. code           
}
  1. 格式化字符串
string inputString("123abc 123.4one two three four");
stringstream ss(inputString);
string s;
int i;
double d;
ss>>i>>s>>d;
cout<<i<<" "<<s.c_str()<<" "<< d ;
while(ss>>s)
    cout<<" "<<s.c_str();
cout<<endl;
//输出123 abc 123.4 one two three four

参考
https://blog.csdn.net/yanyanwenmeng/article/details/82753014
https://blog.csdn.net/mr_chenping/article/details/8224059
https://www.cnblogs.com/wuchanming/p/3906176.html
http://www.runoob.com/cprogramming/c-tutorial.html

猜你喜欢

转载自blog.csdn.net/weixin_43927408/article/details/88254194