如何用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

我需要读取这些行并将它们解析为三个不同的类别:名称(这是一个字符数组),里程(int)和年份(int)。

 sscanf(line, "%[^] %d %d ", name, &mileage, &years);

这对我来说不是很好,有什么建议吗?

问题

传递给sscanf的当前说明符的问题是,它是病态的,即使修复了它也不会做您想要的。如果您使用[^ ]作为第一个转换说明符sscanf将尝试在击中空格之前读取尽可能多的字符。

如果我们假设名称不能包含数字,则指定[^0123456789]将读取正确的数据,但它还将包括名称之后,但在第一个里程条目之前的尾随空格。然而,这很容易通过将name中的最后一个空格替换为空字节来解决。

为了得到读进name的字符数,我们可以使用%n说明符来指示sscanf存储读进匹配实参的字节数;稍后我们可以使用这个值来正确地"trim"我们的缓冲区。

我们还应该指定%[^0123456789]读取的字符的最大宽度,这样它就不会导致缓冲区溢出,这是通过直接在%之后指定缓冲区的大小来完成的。


<

示例实现/strong>

#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] = '';
  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);
}

您可以通过在正确位置插入''来分隔两个变量,如下所示:

pos  = digitPos(line); // This is a pointer to the space
*pos = '';
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的三个原因之一:编写处理重要输入语法的格式规范几乎是不可能的,特别是当您不得不担心从格式错误的输入中恢复时。但还有两个更重要的原因:

  • 许多输入规范,包括你的%[...]结构,就像臭名昭著的gets一样乐于溢出缓冲区。
  • 数字溢出会引发未定义的行为——C库允许崩溃,仅仅因为有人输入了太多数字。

正确的解析这些行的方法是使用strcspn("0123456789", line)while (*p && !isdigit(*p)) p++;扫描第一个数字,然后使用strtoul转换后面的数字。

int pos;
sscanf(line, "%*[^0-9]%n", &pos);
line[--pos]=';';
sscanf(line, "%[^;]; %d %d ", name, &mileage, &years);

相关内容

  • 没有找到相关文章

最新更新