我有一个包含多行的字符串,我想使用sscanf来匹配它的特定部分。但它似乎只能用于匹配第一行中包含的数据。
例如,如果我有字符串:
“age1:x \ r \ n age2:x“
使用sscanf:
sscanf(字符串,“age1:%d”,& i); - 这个工作
sscanf(字符串,“age2:%d”,& j); - 但事实并非如此。
有什么想法吗?
答案 0 :(得分:5)
正如其他人所说,sscanf
不记得读取了多少数据并推进了输入数据,如scanf
和fscanf
。使用%n
说明符记住读取了多少数据,并自行推进输入:
int bytesRead;
if(sscanf(string, "age 1: %d\n%n", &i, &bytesRead) == 1) &&
sscanf(string + bytesRead, "age 2: %d", &j) == 1)
{
// success
}
else
{
// parsing failed
}
%n
说明符说“告诉我到目前为止已读取了多少字节的输入,并将其存储在下一个参数中(必须是指向int
的指针)”。通过将它放在格式字符串的末尾,我们可以计算出解析了多少输入。另请注意,我在%d
之后添加了换行符,以便我们在第一个整数之后吃掉空格;否则,当我们尝试阅读"age 2"
时,它会看到下一个换行符而不是字符a
,并且解析会失败,因为那不匹配。
答案 1 :(得分:1)
sscanf()
sscanf()
都从头开始,'Age2:'与'Age1:'不匹配,因此转换失败。请注意,格式字符串中不属于转换说明符的任何字符都必须完全匹配。因此,当扫描看到'Age2'的2时,它会在字符串中找到'Age1'中的1,并且扫描在该点处失败并且不匹配。唯一的例外是空白区域与任何白色空间序列匹配 - 请参阅下面的代码。
#include <stdio.h>
int main(void)
{
const char string[] = "Age1: 3\r\nAge2: 5\r\n";
const char *scan[] = { "Age1: %d", "Age2: %d", "Age1: %d Age2: %d" };
int age1, age2;
int rc;
if ((rc = sscanf(string, scan[0], &age1)) != 1)
printf("scan failed on '%s'\n", scan[0]);
else
printf("scan passed on '%s' - age %d\n", scan[0], age1);
if ((rc = sscanf(string, scan[1], &age2)) != 1)
printf("scan failed on '%s'\n", scan[1]);
else
printf("scan passed on '%s' - age %d\n", scan[1], age2);
if ((rc = sscanf(string, scan[2], &age1, &age2)) != 2)
printf("scan failed on '%s'\n", scan[2]);
else
printf("scan passed on '%s' - age1 %d, age2 %d\n", scan[2], age1, age2);
return 0;
}
scan passed on 'Age1: %d' - age 3
scan failed on 'Age2: %d'
scan passed on 'Age1: %d Age2: %d' - age1 3, age2 5
答案 2 :(得分:1)
使用sscanf不会像流一样更改字符串,所以在sscanf的第二次调用中,它将开始将age2与age1匹配,并且由于它不匹配,因此不会读取该值。
您可以在第一次阅读内容后进行第二次阅读,也可以一次阅读:
sscanf(string, "age1: %d \n\r age2: %d", &i, &j);
答案 3 :(得分:0)
在完成阅读第一行后,字符串无法记住sscanf的位置。 (如果你想要,你可能想看一下返回值并自己记住它。)
但你可以在一个电话中完成:
sscanf(string, "age1: %d age2: %d", &i, &j);
答案 4 :(得分:-1)
如果你只限于c(即不能使用std :: getline),那么最简单的方法是一次读取一个字符的数据并自己解析。
您可以使用atoi和atof转换任何数字