3

ファイルから構造体に文字列を読み込もうとしていますが、2 つ以上の単語を含む文字列に到達すると、試みているように見えるすべてが機能しません

ファイル内のデータ

「K300」「キーボード」「USジェネリック」 150.00 50

"R576" "16 インチ リム" "トヨタ ヴェロッサ" 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); 

それは私が2日間これに固執していた残りの行をコピーします誰かが私を助けてくれますか、それが可能であれば二重引用符を取り除く方法も教えてください。 (

4

1 に答える 1

7

ではscanf、式%[chars]は括弧内の文字 (または文字範囲) を含む最長の文字列を読み取ります。最初の文字としてのキャレットは、これを逆%[^chars]にします。文字をまったく含まない最長の文字列を読み取ります。したがって、%[^ ]次のスペースまで内容を%[^\n]読み取り、次の新しい行まで内容を読み取ります。

文字列が二重引用符で区切られている場合、最初の引用符を読んでから、次の引用符、最後に最後の引用符まで詰め込む必要があります。

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

この形式はスペースで始まるため、最初の引用符の前の空白は破棄されます。二重引用符自体がエスケープされているため、フォーマット文字列は見苦しく見えます。たとえば、文字列が単一引用符で区切られている場合、コマンドは次のようになります。

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

このアプローチ は、スペースがなくても、文字列が常に引用符で囲まれている場合にのみ機能します。

行全体を読み取り、その行から一致しない引用符をキャッチする方がおそらくクリーンfgetsですsscanf。そうすれば、行を数回スキャンすることもできます.1回目は引用符付きの文字列で、2回目は引用符で囲まれていない文字列です.

編集: スプリアスを含むフォーマット構文を修正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。このようなソリューションには、別のアプローチ、おそらくカスタム スキャン機能が必要です。

于 2013-12-01T17:47:34.683 に答える