3

我正在尝试从文件中读取字符串并进入结构,但是当我到达带有两个或更多单词的字符串时,我似乎尝试的一切都不起作用

文件中的数据

“K300” “键盘” “美国通用” 150.00 50

"R576" "16 英寸轮圈" "Toyota 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); 

它复制了我已经坚持了两天的行的其余部分,有人可以帮助我吗,如果可能的话,如何摆脱双引号我为此尝试了一组不同的代码并且出现了更多错误: (

4

1 回答 1

7

scanf中,表达式%[chars]读取包含括号中的字符(或字符范围)的最长字符串。插入符号作为第一个字符反转:%[^chars]读取不包含任何字符的最长字符串。因此,%[^ ]将内容读取到下一个空格,并将%[^\n]内容读取到下一个新行。

在您的情况下,字符串由双引号分隔,您应该阅读开始引号,然后填充到下一个引号,最后是结束引号:

res = fscanf(in, " \"%[^\"]\"", name);

此格式以空格开头,因此会丢弃第一个引号之前的空格。格式字符串看起来很难看,因为双引号本身被转义了。为了说明,如果您的字符串由单引号分隔,这就是命令的外观。

res = fscanf(in, " '%[^']'", name);

仅当您的字符串始终 用引号括起来时,这种方法才有效,即使它们没有空格。

阅读一整行fgets然后sscanf从该行中捕获不匹配的引号可能会更干净。这样,您还可以多次扫描该行 - 一次用于带引号的字符串,第二次用于未引用的字符串,例如 - 无需多次访问磁盘。

编辑:更正了包含虚假的格式语法,s并更新了第一段中字符串的括号语法描述。

编辑二:因为 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;
}

在这里,该行是从文件中以 forst 读取的。然后,buf扫描该行 ( ) 以获得所需的格式。当然,sscanf必须用fscanf这里代替。出错时,会打印一条简单的错误消息。此消息包括行号和读取错误的字段条目,因此可以在输入文件中找到错误。

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

于 2013-12-01T17:47:34.683 回答