检查格式元素 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:我知道我们可以使用fgets
和strtol
但是这太容易了,在这个项目中我只能使用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" ....
解析字符串
所以,我想用 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:我知道我们可以使用fgets
和strtol
但是这太容易了,在这个项目中我只能使用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" ....