在编码过程中可能会遇到一些需要拆分字符串的地方,但是此时引用一些大型的第三方库如boost::regex库又太麻烦。这个时候使用sscanf是一个很好的选择,它的功能十分强大,可以把字符串按格式拆分,甚至还可以转换类型。
1.拆分字符串
char itemData[10][100] = {0};
const char* strData = "ZM123";
// sscanf第二个参数意为对拆分的格式做出限制
sscanf(strData, "%[A-Z]%[0-9]", itemData[0], itemData[1]);
std::cout<<"Item1:"<<itemData[0]<<" Item2:"<<itemData[1]<<std::endl;
结果为:Item1:ZM Item2:123
%[A-Z]%[0-9]意为在字符串中寻找A到Z的字符并作为输出到第一个参数,直到遇到不是A到Z的字符为止,就去寻找0到9的字符输出到第二个参数。
所以,如果我们使
const char* strData = "ZMaf123";
那么输出结果显而易见就为:Item1:ZM Item2:
后一个参数得不到值。
如果你喜欢的话,可以这样玩,在%后面加上数字对要取的字符长度进行限制。
char itemData[10][100] = {0};
const char* strData = "ZMDAQ";
// sscanf第二个参数意为对拆分的格式做出限制
sscanf(strData, "%2[A-Z]%1[0-9]", itemData[0], itemData[1]);
std::cout<<"Item1:"<<itemData[0]<<" Item2:"<<itemData[1]<<std::endl;
结果输出了Item1:ZM Item2:D
是不是很棒?只要更改第二个参数,就可以简单的截取字符串,但是务必要使%号的数量和输出项数量一致
char itemData[10][100] = {0};
const char* strData = "ZM122DAQ";
// sscanf第二个参数意为对拆分的格式做出限制
sscanf(strData, "%2[A-Z]%*[0-9]%1[A-Z]", itemData[0], itemData[1]);
std::cout<<"Item1:"<<itemData[0]<<" Item2:"<<itemData[1]<<std::endl;
这里出现了一个新的符号%* ,意思为过滤掉指定的字符串,我想你应该会知道结果,对,还是Item1:ZM Item2:D
还有,你可以在第二个参数这样写%[^A-Z]这样就表示除了A到Z的字符会被获取。
2.字符串到int,float型的转换
int m = 0;
const char* strData = "123";
// sscanf第二个参数意为对拆分的格式做出限制
sscanf(strData, "%i", &m);
std::cout<<"m="<<m<<std::endl;
结果为:m=123
很简单 %i表示整数,strData即被转换成为了m,注意对于整数来说作sscanf的参数要加“&”符号。同样,转换成浮点为%f就行。
进行类型转换也可以指定截取字符串的个数,若改为%2i,则m的值就为12;
3.终极应用
假如,有一段ip混杂在一堆英文字符中,这个时候你想把ip的每一段截取出来,第一段转为数字,后面的全转成字符串,该怎么办?
如这样的字符"fdsaferrDDDFAFDSAD192.168.15.12fghDDDDDF";
int firstIP;
char itemData[10][100] = {0};
const char* strData = "fdsaferrDDDFAFDSAD192.168.15.12fghDDDDDF";
// sscanf第二个参数意为对拆分的格式做出限制
sscanf(strData, "%*[A-Za-z]%3i%*[.]%3[0-9]%*[.]%3[0-9]%*[.]%3[0-9]",&firstIP, itemData[0], itemData[1], itemData[2]);
std::cout<<"part1:"<<firstIP<<" part2:"<<itemData[0]<<" part3:"<<itemData[1]<<" part4:"<<itemData[2]<<std::endl;
结果为:part1:192 part2:168 part3:15 part4:12
相信大家可以自己理解。