我有一个输入.txt文件,如下所示:
Robert Hill 53000 5
Amanda Trapp 89000 3
Jonathan Nguyen 93000 3
Mary Lou Gilley 17000 1 // Note that came contains of 3 parts!
Warren Rexroad 72000 7
我需要读取这些行并将它们解析为三个不同的类别:name(这是一个chars数组),mileage(int)和years(int)。
sscanf(line, "%[^] %d %d ", name, &mileage, &years);
这对我来说效果不错,有什么建议吗?
答案 0 :(得分:3)
问题
传递给sscanf
的当前说明符的问题在于它是不正确的,即使修复它也不会做你想要的。如果您使用[^ ]
作为第一个转化说明符,则sscanf
会尝试在点击空格之前读取尽可能多的字符。
如果我们假设名称不能包含指定[^0123456789]
的数字,则会读取正确的数据,但它也会包含名称后面的尾随空格,但是在第一个里程之前进入。但是,通过在name
中用空字节替换最后一个空格可以轻松解决这个问题。
要获取读入name
的字符数,我们可以使用%n
说明符来表示我们{d} sscanf
将读取的字节数存储到匹配的参数中;我们以后可以使用这个值来正确"修剪" 我们的缓冲区。
我们还应该指定%[^0123456789]
读取的字符的最大宽度,以便它不会导致缓冲区溢出,这可以通过指定我们的大小来完成在%
之后直接缓冲。
示例实施
#include <stdio.h>
#include <string.h>
int
main (int argc, char *argv[])
{
char const * line = "Mary Lou Gilley 17000 1";
char name[255];
int mileage, years, name_length;
sscanf(line, "%254[^0123456789]%n %d %d ", name, &name_length, &mileage, &years);
name[name_length-1] = '\0';
printf ("data: '%s', %d, %d", name, mileage, years);
return 0;
}
data: 'Mary Lou Gilley', 17000, 1
答案 1 :(得分:1)
如果你有一个函数可以找到第一个数字的位置,那么:
// This function returns the position of the
// space before the first digit (assuming that
// the names dont contain digits)...
char *digitPos(char *s){
if isdigit(*(s+1)) return s;
else return digitPos(s+1);
}
然后你可以通过在正确的位置插入'\0'
来分开这两个变量,如下所示:
pos = digitPos(line); // This is a pointer to the space
*pos = '\0';
strcpy(name, line);
sscanf(pos + 1, "%d %d", &mileage, &years);
答案 2 :(得分:0)
这可能会帮助您入门。它缺乏BLUEPIXY解决方案的智能,它可以比我的更好地处理拖尾空白(或者你可以自己砍掉它)。
dan@rachel ~ $ echogcc -o t t.c
dan@rachel ~ $ echo "Dan P F 3 21" | ./t
Name: Dan P F ,
Mileage: 3,
Years: 21.
这是代码。
#include <stdio.h>
#include <string.h>
int main(){
char *buf;
int mileage, years;
while(!feof(stdin) ){
if( fscanf( stdin, "%m[^0-9] %d %d", &buf, &mileage, &years) == 3 ){
fprintf(stderr, "Name:\t %s,\nMileage:\t %d,\nYears:\t %d.\n",
buf, mileage, years
);
}
}
}
答案 3 :(得分:0)
您已经发现了*scanf
永远不应该使用的三个原因之一:编写处理非平凡输入语法的格式规范几乎是不可能的,特别是如果您不得不担心从格式错误中恢复输入。但有两个更重要的原因:
%[...]
构造)与臭名昭着的gets
一样高兴地溢出缓冲区。解析这些行的正确方法是使用strcspn("0123456789", line)
或while (*p && !isdigit(*p)) p++;
扫描第一个数字,然后使用strtoul
转换数字接下来。
答案 4 :(得分:-1)
int pos;
sscanf(line, "%*[^0-9]%n", &pos);
line[--pos]=';';
sscanf(line, "%[^;]; %d %d ", name, &mileage, &years);