我正在尝试从文件和结构中读取字符串但是当我到达两个或更多单词的字符串时,我似乎尝试的一切都不起作用
文件中的数据
“K300”“Keyboard”“US Generic”150.00 50
“R576”“16英寸轮圈”“丰田Verossa”800.00 48
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct partInfo {
char number[6];
char name[20];
char description[30];
double price;
int qty;
}Part;
int main() {
char num[6], name[20], desc[30];
int i=0;
int q;
double p;
char ch;
FILE * in = fopen("input.txt", "r");
Part part1;
fscanf(in, " %[^ ]s", &num);
printf("%s\n", num);
fscanf(in, " %[^ ]s", &name);
printf("%s\n", name);
fscanf(in, " %[^ ]s", &desc); //right here only copy "US and not the Generic"
printf("%s\n", desc);
strcpy(part1.number, num);
strcpy(part1.name, name);
strcpy(part1.description, desc);
fclose(in);
return 0;
}
然而,当我尝试使用
时 fscanf(in, " %[^\n]s", &desc);
它复制了剩下的部分 我被困在这两天,有人可以帮助我 以及如果可能的话如何摆脱双引号 我为此尝试了一组不同的代码,并出现更多错误:(
答案 0 :(得分:4)
在scanf
中,表达式%[chars]
读取括号中包含字符(或字符范围)的最长字符串。作为第一个字符的插入符号反转:%[^chars]
读取不包含任何字符的最长字符串。因此,%[^ ]
会将内容读取到下一个空格,%[^\n]
会将内容读取到下一个新行。
在你的情况下,字符串用双引号分隔,你应该阅读开头报价,然后填写下一个报价,最后是结束报价:
res = fscanf(in, " \"%[^\"]\"", name);
此格式以空格开头,因此在第一个引号之前丢弃空格。格式字符串看起来很丑,因为双引号本身是转义的。为了说明这一点,如果您的字符串由单引号分隔,命令将如何显示。
res = fscanf(in, " '%[^']'", name);
只有当您的字符串始终用引号括起来时,此方法才有效,即使它们没有空格。
从该行读取fgets
然后sscanf
的整行以捕获不匹配的引号可能更简洁。这样你也可以多次扫描该行 - 一次是带引号的字符串,另一次是不带引号的字符串,比如说 - 没有多次访问磁盘。
编辑:更正了格式语法,其中包含虚假s
并更新了第一段中字符串的括号语法说明。
编辑II:因为OP似乎对fscanf
的工作原理感到困惑,这里有一个小例子,它逐行从文件中读取部分:
#define MAX 10
#define MAXLINE 240
int main(int argc, char *argv[])
{
FILE *in;
int nline = 0;
Part part[MAX];
int npart = 0;
int res, i;
in = fopen(argv[1], "r"); // TODO: Error checking
for (;;) {
char buf[MAXLINE];
Part *p = &part[npart];
if (fgets(buf, MAXLINE, in) == NULL) break;
nline++;
res = sscanf(buf,
" \"%5[^\"]\" \"%19[^\"]\" \"%29[^\"]\" %lf %d",
p->number, p->name, p->description, &p->price, &p->qty);
if (res < 5) {
static const char *where[] = {
"number", "name", "description", "price", "quantity"
};
if (res < 0) res = 0;
fprintf(stderr,
"Error while reading %s in line %d.\n",
where[res], nline);
break;
}
npart++;
if (npart == MAX) break;
}
fclose(in);
// ... do domething with parts ...
return 0;
}
这里,从文件中读取最后一行。然后,扫描该行(buf
)以获取所需格式。当然,此处必须使用sscanf
代替fscanf
。出错时,会打印一条简单的错误消息。此消息包括行号和读取错误的字段条目,因此错误可以位于输入文件中。
注意sscanf
如何包含最大字段长度,以避免溢出部分的字符串缓冲区。当引用的字符串太长时,会发生扫描错误。让sscanf
读取所有字符并且仅存储前5个字符会更好,但是,sscanf
的工作原理并非如此。这种解决方案需要另一种方法,可能是自定义扫描功能。