检查格式元素 scanf 之前的新行

Check new lines before format element 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它仍然会读取第二个)

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

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);

所以在我这样做之后我意识到 %d 之前的 %c 只读取一个字符,所以如果有 space 然后两者之间换行,它将继续错误地读取文件并且不会检测到错误。 现在我想知道是否有一种方法可以像使用 " %c" 时那样跳过所有 space,同时知道我们是否跳过 \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, stdin) )
                || ( scanf("%d", 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!

if there is a way to skip all spaces

I can only use fscanf to parse the file.

让我们假设 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" ....

解析字符串