在格式元素 scanf

问题描述

所以,我想用fscanf读取两个整数变量中的一些输入,输入必须是

INTEGER ONE SPACE INTEGER \n

例如一个文件可能是这样的:

235 190\n

我想要做的是检查第一个整数或第二个整数之前是否有任何新行,如果是这种情况,则抛出异常:

所以基本上你在这种情况下用 fscanf 所做的就是这样做:

FILE *somefile;
[...]
int w,h;
if (fscanf(somefile,"%d%d") == EOF)
    return (1);

但是这个方法不提供检查整数之间是否有新行

(例如,如果有 INTEGER NEW_LINE INTEGER 它仍然会读取第二个)

因为它在看到数字之前跳过所有空格,所以我设法做的更接近但仍然错误

FILE *somefile;
int w,h;
char check[2];
if (fscanf(somefile,"%d%c%d%c",&w,check,&h,check + 1) == EOF)
    return (-1);
if (check[0] != ' ' || check[1] != '\n')
    return (-1);

所以在我这样做之后我意识到%c之前的%d只是读取一个字符,所以如果两者之间有一个空格然后一个新行,它会继续错误地读取文件并且不会检测到错误。 现在我想知道是否有一种方法可以像使用 " %c" 一样跳过所有空格,同时知道我们是否跳过了 \n。感谢您的帮助。

PS:我知道我们可以使用 fgetsstrtol 但这太简单了,在这个项目中我只能使用 fscanf 来解析文件

解决方法

scanf 愉快地丢弃前导空格以匹配 %d 转换说明符,这使得这有点难以做到。但是您当然可以使用 fgetc(或 getchar)来验证字符,然后将其推回到流中以供 scanf 使用。类似的东西:

$ cat a.c
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

int
main(void)
{
        int c;
        int d[2];
        c = getchar();
        if( 0
                ||!( c == '+' || c == '-' || isdigit(c))
                || ( c != ungetc(c,stdin) )
                || ( scanf("%d",d) != 1 )
                || ( getchar() != ' ' )
                || ( (c = getchar()) == EOF )
                ||!( c == '+' || c == '-' || isdigit(c))
                || ( c != ungetc(c,d + 1) != 1 )
                || ( getchar() != '\n' )
        ){
                fprintf(stderr,"invalid input!\n");
                return EXIT_FAILURE;
        }
        printf("Read %d %d\n",d[0],d[1]);

        return EXIT_SUCCESS;
}
$ gcc a.c
$ printf '5 28\n' | ./a.out
Read 5 28
$ printf '5  28\n' | ./a.out
invalid input!
$ printf ' 5 28\n' | ./a.out
invalid input!
$ printf ' 5 28' | ./a.out
invalid input!
,

如果有办法跳过所有空格

我只能使用 fscanf 来解析文件。

让我们假设 ungetc() 是不允许的 - 这让事情变得更难。


"%d" 愉快地消耗所有(0 个或更多)前导空格,包括 '\n',恕不另行通知。

首先使用 fscanf("%[...]") 查找前导空格。 usual suspects" \t\n\r\f\v"

// Consume leading whitespaces 
// Return
// 1: \n or EOF found
// 0: not found
int EatLeadingWS(FILE *f) {
  int count;
  char space[2];
  while ((count = fscanf("%1[ \t\n\r\f\v]",space)) == 1) {
    if (space[0] == '\n') return 1;
  }
  return count == EOF;
}

替代方案:使用 "%c"isspace(),但是我们需要一种方法将非空格放回原处。

然后在 "%d" 之前寻找空格

int some_int;
if (EatLeadingWS(f) == 0) {
  int count;
  if ((count = fscanf("%d",&some_int)) == 1) { 
    printf("int %d found before a \\n\n",some_int);
  }
}
  

另一种选择是使用 char buf[100]; fscanf("%99[^\n]",buf) 读取大部分行,然后使用 sscanf(buf,"%d%1[ ]%d" .... 解析字符串