[英]How to parse an input line with sscanf?
我有一个输入.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
我需要阅读这些行并将其解析为三个不同的类别:名称(这是一个字符数组),Mileage(int)和years(int)。
sscanf(line, "%[^] %d %d ", name, &mileage, &years);
这对我来说不是很好,有什么建议吗?
问题
当前传递给sscanf
说明符的问题在于,它们既格式不正确,即使被修复,也无法满足您的要求。 如果您将[^ ]
用作第一个转换说明符 ,则sscanf
将尝试在插入空格之前读取尽可能多的字符。
如果我们假设一个名称不能包含数字,则指定[^0123456789]
将读取正确的数据,但它还将在名称之后但在第一个里程输入之前包含尾随空格。 但是,可以通过将name
的最后一个空格替换为空字节来轻松解决。
为了获得读入name
的字符数,我们可以使用%n
说明符来表示我们将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
如果您有一个可以找到第一个数字的位置的函数,如下所示:
// 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);
这可以帮助您入门。 它缺乏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
);
}
}
}
您已经发现*scanf
永远不要使用*scanf
的三个原因之一:编写处理非平凡输入语法的格式规范几乎是不可能的,尤其是在您必须担心从格式错误的输入中恢复时。 但是,还有两个更重要的原因:
%[...]
建设,也同样高兴地溢出缓冲区声名狼藉gets
。 解析这样的行的正确方法是使用strcspn("0123456789", line)
或while (*p && !isdigit(*p)) p++;
扫描第一个数字while (*p && !isdigit(*p)) p++;
,然后使用strtoul
转换strtoul
的数字。
int pos;
sscanf(line, "%*[^0-9]%n", &pos);
line[--pos]=';';
sscanf(line, "%[^;]; %d %d ", name, &mileage, &years);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.