[英]How to use fscanf() to get strings of multiple format?
说这是我要阅读的文件:
07983988 REMOVE String1
13333337 ADD String4 100
34398111 TRANSFER String5 String6 100
这些是仅有的3种有效格式。
我正在使用以下代码块来检查解析的行的格式是什么:
// Read from file.
while (!feof(fd)) {
// Check for format.
if (fscanf(fd, "%d %s %s %s %lf", ×tamp, transaction_type_str, company1, company2, &value)) {
node_t *transaction = create_node((long int)timestamp, 1, company1, company2, value);
add_node(transactions, transaction);
} else if (fscanf(fd, "%d %s %s", ×tamp, transaction_type_str, company1)) {
node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, 0);
add_node(transactions, transaction);
} else if (fscanf(fd, "%d %s %s %lf", ×tamp, transaction_type_str, company1, &value)) {
node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, value);
add_node(transactions, transaction);
}
但是,这给了我无限循环。 我是C语言中的文件I / O的新手,我想知道使用标记化方法还是基于行的格式搜索方法是否更好。
在大纲中:
char buffer[4096];
while (fgets(buffer, sizeof(buffer), fd) != 0)
{
int offset;
if (sscanf(buffer, "%d %s %n", ×tamp, transaction_type_str, &offset) == 2)
{
char *residue = buffer + offset;
if (strcmp(transaction_type_str, "REMOVE") == 0)
{
if (sscanf(residue, "%s", company1) == 1)
…process remove…
else
…report error, etc…
}
else if (strcmp(transaction_type_str, "ADD") == 0)
{
if (sscanf(residue, "%s %lf", company1, &value) == 2)
…process add…
else
…report error, etc…
}
else if (strcmp(transaction_type_str, "TRANSFER") == 0)
{
if (sscanf(residue, "%s %s %lf", company1, company2, &value) == 3)
…process transfer…
else
…report error, etc…
}
else
{
…report error and continue or break…
}
}
}
您可以使分析更加严格,例如,坚持要求在辅助sscanf()
调用完成之后没有未使用的数据,等等。这很奇怪,但绝非不可能。
它涵盖了请求的代码-在分析该行的其余部分之前,它确定请求的交易类型。
问题是您将feof测试用作while控件。 这是它不起作用的原因。
为什么“ while(!feof(file))”总是错误的?
该功能测试文件结束指示符,而不是流本身。 这意味着另一个功能实际上负责设置指示已达到EOF的指示器。 通常可以通过执行读取EOF的功能来完成此操作。 然后,我们可以将问题跟踪到该函数,并且发现大多数读取函数在读取完所有数据后便会设置EOF,然后执行最终读取,结果是没有数据,只有EOF。
考虑到这一点,它如何在我们的代码片段中表现为一个错误? 很简单...程序在循环中获取最后一行数据时,fgets()可以正常工作,而无需设置EOF,我们可以打印出数据。 循环返回到顶部,对feof()的调用返回FALSE,我们再次开始循环。 这次,fgets()看到并设置了EOF,但是由于我们的逻辑欠佳,我们仍然继续处理该缓冲区,而没有意识到其内容现在是未定义的(很可能在上一个循环中未触及)。
使用fgets()
,然后使用带有" %n"
说明符的sscanf()
来检测扫描完成。
通过检测扫描是否到达末尾并且在线上没有其他文本,我们可以进行清晰而对称的解析检测。 很像OP的原始代码。
#define BUFSIZE 200
char buf[BUFSIZE];
while (fgets(buf, sizeof buf, fd) != NULL) {
int n = 0;
if (sscanf(buf, "%d %s %s %s %lf %n",
×tamp, transaction_type_str, company1, company2, &value, &n));
if (n > 0 && buf[n] == '\0') {
node_t *transaction = create_node((long int)timestamp, 1, company1, company2, value);
add_node(transactions, transaction);
continue;
}
n = 0;
sscanf(buf, "%d %s %s %n",
×tamp, transaction_type_str, company1, &n));
if (n > 0 && buf[n] == '\0') {
node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, 0);
add_node(transactions, transaction);
continue;
}
n = 0;
sscanf(buf, "%d %s %s %lf %n",
×tamp, transaction_type_str, company1, &value, &n);
if (n > 0 && buf[n] == '\0') {
node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, value);
add_node(transactions, transaction);
continue;
}
Handle_BadLine(buf); // do not use transaction_type_str, company1, company2, value, n
}
注意:使用"%s"
是危险的。 最好限制宽度
char transaction_type_str[20];
...
sscanf(buf, "%d %19s ...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.