C语言-unix环境下的fscanf和sprint命令

发布于 2024-09-05 10:42:41 字数 483 浏览 2 评论 0原文

我正在尝试读取 30 行 5 列且分隔符为“制表符”的文件。每次我只得到部分行。 在windows环境下运行良好。知道为什么它在 UNIX 中不起作用吗?

while (fscanf(FFMapFile, "%s\t%s\t%s\t%s\t%s\t", fnfMap[i].COS_ID, fnfMap[i].FF_First_Act, fnfMap[i].FF_Next_Act, nfMap[i].Free_FF_allowed, fnfMap[i].FF_Change_Charge) != EOF)
{ 
    sprintf(s,"%s\t%s\t%s\t%s\t%s\t", nfMap[i].COS_ID, fnfMap[i].FF_First_Act, fnfMap[i].FF_Next_Act, fnfMap[i].Free_FF_allowed, fnfMap[i].FF_Change_Charge);
    error_log(s,ERROR);
    i++; }

I am trying to read file with 30 rows and 5 columns with separator of "tab". Each time I get only part of the rows.
In the windows environment it's working good. Any idea why in unix it is not working?

while (fscanf(FFMapFile, "%s\t%s\t%s\t%s\t%s\t", fnfMap[i].COS_ID, fnfMap[i].FF_First_Act, fnfMap[i].FF_Next_Act, nfMap[i].Free_FF_allowed, fnfMap[i].FF_Change_Charge) != EOF)
{ 
    sprintf(s,"%s\t%s\t%s\t%s\t%s\t", nfMap[i].COS_ID, fnfMap[i].FF_First_Act, fnfMap[i].FF_Next_Act, fnfMap[i].Free_FF_allowed, fnfMap[i].FF_Change_Charge);
    error_log(s,ERROR);
    i++; }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蒲公英的约定 2024-09-12 10:42:41

fscanf() 字符串中的 \t 字符不是必需的 - 制表符是空格,因此您也可以说“%s%s%s%s” - 可以想象,两个 scanf 实现对它们的处理方式不同。另外,您应该检查 fscanf 返回的值不是 EOF 但不等于预期的转换次数,这表明存在某种转换错误。

The \t characters in your fscanf() string are not necessary - tabs are whitespaces, so you may just as well say "%s%s%s%s" - conceivably, the two scanf implementations are treating them differently. Also, you should be checking for fscanf returning a value other than EOF but not equal to the number of expected conversions, which would indicate a conversion error of some sort.

ぺ禁宫浮华殁 2024-09-12 10:42:41

更仔细地检查 fscanf() 的返回值;例如,如果匹配 3 个字段,它将返回 3。您可能需要小心各种字符串的大小以避免缓冲区溢出 - 但这可能是另一天的主题。

令我震惊的可能性是,格式字符串中的最后一个制表符可能作为换行符更好 - 但 fscanf() 通常对格式字符串和数据中的空白采取相当自由的态度。

这个简化的(但完整的、有效的)代码版本在 MacOS X 上表现或多或少是理智的。

#include <stdio.h>

int main(void)
{
    char b1[20], b2[20], b3[20], b4[20], b5[20];
    while (fscanf(stdin,"%s\t%s\t%s\t%s\t%s\t", b1, b2, b3, b4, b5) == 5)
        printf("%s\t%s\t%s\t%s\t%s\n", b1, b2, b3, b4, b5);
    return 0;
}

但是,它确实将字符串“kkkk k”(由空格分隔的 5 个单个字母)视为等效于由 5 个选项卡分隔。因此,问题在于 C 标准的第 §7.19.6.2 节规定:

该格式由零个或多个指令组成:一个或多个空格
字符、普通多字节字符(既不是 % 也不是空白字符)或
转换规范。

跳过输入空白字符(由 isspace 函数指定),除非
该规范包括 [、c 或 n 说明符。

另外,关于“%s”说明符,它说:

匹配一系列非空白字符。

要强制匹配实际选项卡,您必须更加努力。诉诸“将一行读入缓冲区(fgets()”)并手动拆分它会更容易。这还允许您在一行上强制使用 5 个单词,如果字段太少或太多,您可能会生成错误或警告。使用fscanf(),您无法做到这一点。如果您在一行上输入 8 个单词,它会第一次读取前五个单词,然后是该行剩余的三个单词,加上下一行的前两个单词,依此类推。

Check the return value from fscanf() more carefully; it will return, for example, 3 if it matches 3 fields. You might want to be careful about the sizes of the various strings to avoid buffer overflows - that is, however, probably a subject for another day.

The possibility which strikes me is that the last tab in the format string might be better as a newline - but fscanf() normally takes a fairly liberal attitude towards white space in the format strings and data.

This simplified (but complete, working) version of your code behaves more or less sanely on MacOS X.

#include <stdio.h>

int main(void)
{
    char b1[20], b2[20], b3[20], b4[20], b5[20];
    while (fscanf(stdin,"%s\t%s\t%s\t%s\t%s\t", b1, b2, b3, b4, b5) == 5)
        printf("%s\t%s\t%s\t%s\t%s\n", b1, b2, b3, b4, b5);
    return 0;
}

However, it did treat a string 'k k k k k' (5 single letters separated by blanks) as equivalent to separated by 5 tabs. The problem, therefore, is that section §7.19.6.2 of the C standard specifies:

The format is composed of zero or more directives: one or more white-space
characters, an ordinary multibyte character (neither % nor a white-space character), or a
conversion specification.

Input white-space characters (as specified by the isspace function) are skipped, unless
the specification includes a [, c, or n specifier.

Also, with regards to the '%s' specifier, it says:

Matches a sequence of non-white-space characters.

To force matching of actual tabs, you'd have to work quite a bit harder. It would be much easier to resort to the 'read a line into a buffer (fgets()) and split it manually'. This will also allow you to enforce 5 words on a line and you can generate an error or warning if there are too few or too many fields. With fscanf(), you cannot do that. If you type 8 words on a line, it will read the first five the first time, then the remaining three words on the line plus the first two on the next, and so on.

一花一树开 2024-09-12 10:42:41

成功后,fscanf 返回成功读取的项目数。
该计数可以与预期数量匹配,或者在匹配失败的情况下更少。

您应该检查 fscanf 的返回值以查看哪一行未正确解析并检查您的输入数据。

On success, the fscanf returns the number of items succesfully read.
This count can match the expected number or be less in case of a matching failure.

You should check fscanfs return value to see which line isn't parsed correctly and examine your input data.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文