如何在C语言中从文件的双引号中读取多个单词

如何在C语言中从文件的双引号中读取多个单词,c,struct,scanf,c-strings,character-arrays,C,Struct,Scanf,C Strings,Character Arrays,我试图从文件中读取字符串并将其读入结构,但当我读入包含两个或更多单词的字符串时,我尝试的一切都不起作用 文件中的数据 “K300”键盘“美国通用”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 nam

我试图从文件中读取字符串并将其读入结构,但当我读入包含两个或更多单词的字符串时,我尝试的一切都不起作用

文件中的数据

“K300”键盘“美国通用”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;
}
它复制行的其余部分 我已经被困在这两天了有人能帮我吗 如果可能的话,如何去掉双引号呢
我为此尝试了一组不同的代码,但出现了更多错误:(

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;
}
#定义最大值10
#定义MAXLINE 240
int main(int argc,char*argv[])
{
文件*in;
int-nline=0;
部分[最大值];
int npart=0;
int res,i;
in=fopen(argv[1],“r”);//TODO:错误检查
对于(;;){
char buf[MAXLINE];
零件*p=&零件[npart];
如果(fgets(buf,MAXLINE,in)=NULL)中断;
nline++;
res=sscanf(buf,
“\%5[^\“]\”\%19[^\“]\”\%29[^\“]\%lf%d”,
p->编号,p->名称,p->说明,&p->价格,&p->数量);
如果(res<5){
静态常量字符*其中[]={
“编号”、“名称”、“说明”、“价格”、“数量”
};
如果(res<0)res=0;
fprintf(标准,
“读取第%d行中的%s时出错。\n”,
其中[res],nline);
打破
}
npart++;
如果(npart==最大值)中断;
}
fclose(in);
//…用零件做一些事情。。。
返回0;
}
这里,从文件中读取forst行。然后,该行(
buf
)扫描所需格式。当然,这里必须使用
sscanf
而不是
fscanf
。出错时,会打印一条简单的错误消息。该消息包括行号和读取出错的字段条目,因此可以在输入文件中找到错误


请注意
sscanf
如何包括最大字段长度以避免溢出部件的字符串缓冲区。当引用的字符串太长时会发生扫描错误。让
sscanf
读取所有字符并仅存储前5个字符会更好,但
sscanf
不是这样工作的。这样的解决方案需要这是另一种方法,可能是一种自定义扫描功能。

使用
fgets()
strtok()
而不是
fscanf()
,永远不要回头看。请写标准英语,包括大写字母。我的格式规范中有一个错误。括号符号替换了
%s
,因此它是
%[chars]
,而不是
%[chars]s
。我已经更新了我的答案。如何让它正确读取第二行数据?当再次运行fscanf时,它不会转到文件中的下一行。
fscanf
逐个读取标记。扫描成功后,文件偏移量位于匹配的格式之后。
fscanf
还将新行字符视为e空格,因此它不按行读取。您只读取三个引号分隔的字符串,但不读取末尾的两个数字。您认为您读取了下一行,但实际上您尝试从数字150.00中读取引号分隔的字符串。格式似乎是行绑定的,因此最好是将每一行d然后
sscanf
或在您的行读取代码后执行
fgets
,将文件前进到下一行。当您读取csv文件时,所有内容都是字符串。因此您不能使用数字类型或数字格式规范。这实际上使解析csv更加简单。
#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;
}