背景:欲从FTP服务器下载一文件,须知其大小,使用SIZE命令无效(该命令在RFC959中未出现,即非标准命令)。经测试发现RETR命令返回的信息中包含了文件大小,即字节数,现需要将其从字符串中解析出来。
PS:本人是写代码的,并非使用工具的。
信息如:"150 Opening BINARY mode data connection for latelee.dat (29068 bytes)\r\n\0"
后面写出“\r\n\0”没其它意思,只表明该命令以\r\n结尾,为一正常字符串(以'\0'结束)。
方法1:逐一解析该字符串,遇到左括号作一标志,遇到右括号作一标志,中间者即为我们所需要字符串,再从中解析出数字。示意代码(示意而已,非实际用中)如下:
for (int i = 0; foo[i] != '\0'; i++)
{
if (foo[i] == '(')
{
do {
buf[j++] = foo[i++];
} while (foo[i] != ')');
buf[j++] = '\0';
}
}
方法2:使用字符串操作函数,示意代码如下:
char buf1[32];
char *p1, *p2;
p1 = strchr(foo, '(') + 1;
p2 = strchr(foo, ')') -1;
strncpy(buf1, p1, p2-p1);
buf1[p2 - p1] = '\0';
方法3:使用sscanf函数,这个函数很早就留意到了,只是没使用它的高级用法。所谓高级者,大部分时间不使用,一旦使用到,便觉得神奇,正如某人低调刻苦研究,不为人所知,突然搞出一重大成果,便一举成名。
关于sscanf函数,网上有资料,不过绝大部分都基本同一版本演绎,以“sscanf用法”为关键字google即可找到多篇相同文章。此处结合前面提出的问题说一下我对它的理解(其实没有理解,只使用它解决问题而已)。
示意代码如下:
char foo[] = "150 Opening BINARY mode data connection for latelee.dat (29068 bytes)";
char buf[32];
int size = 0;
sscanf(foo, "%*[^(](%s[^)]", buf);
sscanf(foo, "%*[^(](%d[^)]", &size);
其中buf为一数组,size为整型(不是整形)类型。结果都能输出29068,前者是一个字符串,后面的是整型数据。buf实际数据为"29068\0",以'\0'结束,可放心使用。
sscanf似乎是以单词为单位,本来是输出"29068 bytes”然而后面的bytes并没有存储到buf中,“%*[^(]”表示过滤掉“(”前面所有字符,直到遇到“(”为止,%s与%d分别表示以字符串、整型存储,注意它们前面还有一个“(”,这个是必须的,不然会被识别为"(29068"的,后面的“[^)]”表示直到遇到右括号“)”为止——不过似乎改写成“[^ ]”更好一些,即遇到空格符号为止。
此法针对某一固定格式的字符串,个人认为使用sscanf还是挺好的,虽然没有比较过上面几种方法的效率,但个人更喜欢使用sscanf函数。
2013-05-09补记:
最近又遇到需要使用sscanf的情况,下面简单写一下。
问题:uboot在启动时需要写日志,该日志存放到EEPROM,并且带有时间信息,现在为了处理时间,需要将时间信息解析出来。
方法:使用scanf一一解析出时间及其它信息。
举例:
int year, month, day, hour, min, sec;
char p[] = "2000-01-01 01:35:02:come on!! hello world!!!";
char tmp[128] = {0};
printf("org: %s\n", p);
sscanf(p, "%04d-%02d-%02d %02d:%02d:%02d%[ -~]", &year, &month, &day, &hour, &min, &sec, tmp);
//strcpy(tmp, p + 19);
printf("%04d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, min, sec);
year += 1;
day += 1;
sprintf(p, "%04d-%02d-%02d %02d:%02d:%02d%s", year, month, day, hour, min, sec, tmp);
printf("new: %s\n", p);
结果:
org: 2000-01-01 01:35:02:come on!! hello world!!!
2000-01-01 01:35:02
new: 2001-01-02 01:35:02:come on!! hello world!!!
说明:主要遇到的问题是如何解析时间后面的字符串,因为这个字符串有空格,所以scanf不用直接用%s。上面的方法是%[ -~],把所有的打印的ASCII字符都读到缓冲区中。
至于为什么要这样做,后面有空再写篇文章出来。