fscanf()可以读取空格符吗?

6
我已经有一些代码使用fscanf()读取文本文件,现在我需要修改它以使以前无空白的字段允许空格。文本文件基本上是这种形式: ``` title: DATA title: DATA 等等... ``` 基本上使用`fgets(inputLine, 512, inputFile); sscanf(inputLine, "%*s %s", &data);`解析数据字段并忽略标题,但现在一些数据字段需要允许空格。我仍然需要忽略标题和紧随其后的空格,但是然后读取剩余的行,包括空格。
有没有办法使用sscanf()函数做到这一点?
如果不行,那么我可以进行最小的代码更改来正确处理空格吗?
更新:我编辑了问题以将fscanf()替换为fgets()+ sscanf(),这实际上是我的代码正在使用的内容。当我第一次写问题时,我认为这不相关,所以我简化了它到fscanf()。

如果您曾经使用scanf解析它,那么您以前也可以解析类似于title: DATA title: DATA(即全部在一行上)的内容。如果您想在值中允许空格,那么终止符将是什么?如果是换行符,那么似乎您的原始代码有点太松散了... - Pavel Minaev
另外,您如何决定str缓冲区的大小,并确保它不会溢出? - Pavel Minaev
是的,当数据中可能包含空格时,换行符将被用作终止符。 - Graphics Noob
6个回答

14

如果您无法使用 fgets(),则可以使用 %[ 转换说明符(带有“排除选项”):

char buf[100];
fscanf(stdin, "%*s %99[^\n]", buf);
printf("value read: [%s]\n", buf);

但是 fgets() 更好。


编辑:使用fgets()+sscanf()版本

char buf[100], title[100];
fgets(buf, sizeof buf, stdin); /* expect string like "title: TITLE WITH SPACES" */
sscanf(buf, "%*s %99[^\n]", title);

4
对于这个特定的案例,fgets如何更好? - Pavel Minaev
1
嗯...需求一直在变化(首先字符串中没有空格)。对于这种特殊情况来说,这并不更好,但现在最好使用fgets(),以预期下一个需求的变化 :) - pmg
这个 %[ 的东西是标准的 C89 吗?我以前从没见过。 - Calmarius
2
@Calmarius:是的,它是标准的C89。我没有C89的参考资料,但你可以在标准C99的7.19.6.2中了解相关内容。 - pmg
等一下...这是C89标准中4.9.6.2的链接:http://port70.net/~nsz/c/c89/c89-draft.html#4.9.6.2 - pmg
显示剩余3条评论

3
最简单的方法是发出一个
fscanf("%*s");

丢弃第一部分,然后只调用fgets:

fgets(str, stringSize, filePtr);

3

我强烈建议您停止使用fscanf(),转而使用fgets()(它可以读取整行),然后解析已读取的行。

这将使您在解析非精确格式输入方面拥有更多自由。


我更新了问题,以显示我实际上确实使用fgets(),但我不明白它到底有什么帮助。我读入后仍然需要解析该行。 - Graphics Noob
1
当你获得整个字符串之后,最好手动遍历它而不是使用sscanf。 - Anon.
是的,使用指针来完成,或者更好的方法是使用正则表达式。如果您使用C ++,我会建议使用boost;我不知道有哪些好的C库,但肯定有一些。我听说POSIX支持它们。 - Andreas Bonini

3

如果您坚持使用scanf,并且假设您希望换行符作为终止符,则可以这样做:

scanf("%*s %[^\n]", str);

请注意,上述代码如果完全按照原样使用是不好的,因为没有防止`str`溢出(因为`scanf`不知道其大小)。当然,您可以设置预定义的最大大小并指定它,但这可能会导致您的程序在某些有效输入上无法正常工作。
如果行的大小由输入格式定义而不受限制,则您唯一实用的选择是使用`fgetc`逐个字符地读取数据,并随着读取的进行定期重新分配缓冲区。如果您这样做,那么修改它以删除所有读取的字符直到第一个空格相当容易。

3

fscanf中的%s占位符会跳过输入中的任何空格,然后读取一串非空格字符直到下一个空格字符之前。

如果您想读取到换行符,可以使用%[^\n]作为占位符。此外,格式字符串中的空格将跳过输入中的空格。因此,如果您使用以下代码:

fscanf("%*s %[^\n]", &str);

它将读取行上的第一件事情,直到第一个空格(在您的情况下为“标题:”),然后将其丢弃,然后读取空格字符并将其丢弃,然后将所有字符读取到换行符中的str中,这听起来像是您想要的。

请注意,str不会溢出-您可能希望使用

fscanf("%*s %100[^\n]", &str)

限制最大字符串长度,以便您读取(100个字符,不包括这里的终止NUL)。

我知道这只是一个简短的例子,但你必须使用str的地址吗?我认为这也可以工作。fscanf("%*s %[^\n]", str); - cokedude

1
你正在遇到*scanf系列函数的限制。通过相对较小的更改,您可以尝试使用Dave Hanson的C Interfaces and Implementations中的字符串扫描模块。这些东西是从编程语言Icon中进行了改装的,它是一种极其简单和强大的字符串处理语言,Hanson和其他人在亚利桑那州工作过。与sscanf的区别不会太大,而且它比正则表达式更简单、更易于使用、更强大。唯一的缺点是没有这本书,代码有点难以理解——但如果您经常进行C编程,这本书是非常值得拥有的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接