2017-06-15 2 views
-2

私の理解するために、すべての行の文字列の長さを知らなくても、fscanfは使用方法、解析する方法があり、入力よう:

000000 $出口$$$ 16
Cheitとそのお仕置き$$$ 8
戦争とサッカー$$$ 12の
超短パルス $$$ 8
非線形光学$$$ 8
などを再生するにはどのように戦争$$$ 12
の記念$$$ 12の
風..

"$$$"はデータのフィールド間を区切ります。
私はフレーズアップグレードするために探しています:それはノーライン収まるでしょう

sscanf(line, " %200[^$][^$][^$]$$$%ld", name, &copies); 

を。 1である。

EDIT:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#define NAME_LENGTH 200 
#define ERROR -1 
typedef int BOOL; 
#define TRUE 1 
#define FALSE 0 

typedef struct book{ 
    char name[NAME_LENGTH]; 
    long copies; 
    struct book *next; 
} Book; 

Book* create_book(char name[], long copies){ 
    Book *new_book = (Book*) malloc(sizeof(Book)); 
    if (new_book != NULL) { 
     strcpy(new_book->name, name); 
     new_book->next = NULL; 
     new_book->copies = copies; 
    } 
    return new_book; 
} 

Book* add_first(Book *head, char name[], long copies){ 
    Book *new_book = create_book(name, copies); 
    if (new_book == NULL) 
     return NULL; 
    new_book->next = head; 
    return new_book; 
} 

Book* add_last(Book *head, char name[], long copies){ 
    Book *tail; 
    Book *new_book = create_book(name, copies); 
    if (new_book == NULL) 
     return NULL; 
    if (head == NULL) 
     return new_book; 
    tail = head; 
    while (tail->next != NULL) 
     tail = tail->next; 
    tail->next = new_book; 
    return head; 
} 

Book* add_sorted(Book *head, char name[], long copies){ 
    Book* iter, *prev = NULL; 
    Book* new_book = create_book(name, copies); 
    if(new_book == NULL) 
     return head; 
    if (head == NULL) 
     return new_book; 
    if (!strcmp(new_book->name, head->name)){ 
     new_book->next = head; 
     return new_book; 
    } 
    iter = head; 
    while ((iter != NULL) && (strcmp(new_book->name, head->name))){ 
     prev = iter; 
     iter = iter->next; 
    } 
    prev->next = new_book; 
    new_book->next = iter; 
    return head; 
} 

int length(const Book *head){ 
    if (head == NULL) 
     return 0; 
    return 1 + length(head->next); 
} 

void free_library(Book *head_book){ 
    if (head_book == NULL) 
     return; 
    free_library(head_book->next); 
    free(head_book); 
} 

Book* find_book(Book *head, char name[]){ 
    if (head == NULL) 
     return NULL; 
    if (strcmp(head->name, name) == 0) 
     return head; 
    find_book(head->next, name); 
    return NULL; 
} 

Book* delete_book(Book *head, char name[]){ 
    Book *iter = head, *prev = NULL; 
    if (head == NULL) 
     return head; 
    if ((!strcmp(head->name, name)) == 1){ 
     iter = head->next; 
     free(head); 
     return iter; 
    } 
    while (iter->next != NULL){ 
     if ((!strcmp(head->name, name)) == 1){ 
      prev->next = iter->next; 
      free(iter); 
      break; 
     } 
     prev = iter; 
     iter = iter->next; 
    } 
    return head; 
} 

Book* initBooksList(FILE *input){ 
    Book *head_book = NULL, *existing_book = NULL; 
    long copies = 0; 
    char line[256] = {0}, name[NAME_LENGTH]; 
    if (input == NULL){ 
     printf("File did not open. Exit..\n"); 
     return NULL; 
    } 
    while(!feof(input)){ 
     if((fgets(line, 256, input) != NULL) && (head_book == NULL)){ 
      sscanf(line, " %200[^$][^$][^$]$$$%ld", name, &copies); 
      printf("%s\n%ld\n", name, copies); 
      head_book = create_book(name, copies); 
      strcpy(line, ""); 
      strcpy(name, ""); 
      copies = 0; 
     } 
     else{ 
      sscanf(line, " %200[^$][^$][^$]$$$%ld", name, &copies); 
      existing_book = find_book(head_book, name); 
      if(existing_book != NULL){ 
       existing_book->copies += copies; 
       printf("%s\n%ld\n", name, existing_book->copies); 
      } 
      else{ 
       add_sorted(head_book, name, copies); 
       printf("%s\n%ld\n", name, copies); 
       strcpy(line, ""); 
       strcpy(name, ""); 
       copies = 0; 
      } 
     } 
    } 
    return head_book; 
} 

void storeBooks(Book *head_book){ 

} 

void returnBook(Book *head_book){ 

} 

void borrowBook(Book *head_book){ 

} 

int main(int argc, char *argv[]){ 
    int i = 0; 
    FILE *ptr; 
    printf("%d\n", argc); 
    for(i = 0; i < argc; i++) 
     printf("argv[%d] = %s\n", i, argv[i]); 
    ptr = fopen(argv[1], "r"); 
    initBooksList(ptr); 
    return 0; 
} 
+1

通常のアプローチが使用することであるstrstr()string.hであることに注意してください'fgets'を使って行全体を適切な大きなバッファに読み込み、' sscanf'/'strtok'/whateverを使いますそれを解析する。 –

+2

試しましたか?提示するコードはありますか? – Gam

+1

*最大*行の長さはありますか?そして、私は 'fscanf'(およびファミリー)が正しい選択であるかもしれないと確信していません...代わりに、おそらく' fgets'と 'strstr'で何かをするでしょう。 –

答えて

0

最長タイトルがyour commentに示されているように200文字であることがわかっている場合は、これにヌルターミネータのスペースを含めて配列を割り当てることができます。

fscanf()を使用すると、ファイルの行をフォーマット文字列" %200[^$]$$$%d"で解析できます。最初のスペースは、fscanf()に先行するI/O操作の後ろに残っている可能性のある先頭の空白をスキップするよう指示します。次の変換指定子は%200[^$]で、$になるまで、fscanf()に文字列を読み込むように指示します。 $は入力ストリームに残されます。ここではバッファオーバーフローを防ぐために最大幅200を指定しています。書式文字列の次の3文字($$$)が入力に存在し、最後の変換指定子、%dに達する前に一致する必要があります。入力ファイルに対して実行したときにここで

#include <stdio.h> 
#include <stdlib.h> 

#define MAX_TITLE 201 

int main(void) 
{ 
    /* Open file, and check for success */ 
    FILE *fp = fopen("data.txt", "r"); 
    if (fp == NULL) { 
     perror("Unable to open file"); 
     exit(EXIT_FAILURE); 
    } 

    char title[MAX_TITLE]; 
    int price; 

    while (fscanf(fp, " %200[^$]$$$%d", title, &price) == 2) { 
     printf("Title: %s --- Price: $%d\n", title, price); 
    } 

    fclose(fp); 

    return 0; 
} 

は、プログラムの出力です:

Title: The Cheit and its Punishment --- Price: $8 
Title: War and Remembrance --- Price: $12 
Title: Winds of War --- Price: $12 
Title: How to Play Football --- Price: $12 
Title: Ultrashort Pulses --- Price: $8 
Title: Nonlinear Optics --- Price: $8 

上記のコードでfscanf()への呼び出しは、入力ストリーム内の各ラインの最後の数以下の空白文字を残します。これが、フォーマット文字列の先頭の空白が必要だった理由です。より良い解決策は、入力の行をフェッチするのにfgets()を使用し、行を解析するためにsscanf()を使用することです。 bufferは、読み込まれるごとに各行の内容を保持するように割り当てる必要があります。入力ストリームに長い文字が残っている可能性を減らすので、ここでは十分な割り当てが行われます。入力が長くなる可能性がある場合は、次のfgets()の呼び出しの前に入力ストリームを消去するコードを追加する必要があります。

このアプローチの利点の1つは、\nを含む行全体が読み取られるため、以前のように先行する空白文字をスキップする必要がないことです。もう1つの利点は、最後の数字の後にある偽の文字を無視したり、コードで処理できることです。ラインが格納されているので、必要に応じて何度でも検査してスキャンすることができます。最終的な数字に続く文字は、先頭の空白をスキップするために用意された最初のバージョンでは問題を引き起こしていました。ここ

#include <stdio.h> 
#include <stdlib.h> 

#define BUF_SZ  1000 
#define MAX_TITLE 201 

int main(void) 
{ 
    /* Open file, and check for success */ 
    FILE *fp = fopen("data.txt", "r"); 
    if (fp == NULL) { 
     perror("Unable to open file"); 
     exit(EXIT_FAILURE); 
    } 

    char buffer[BUF_SZ]; 
    char title[MAX_TITLE]; 
    int price; 
    size_t lnum = 0; 

    while (fgets(buffer, BUF_SZ, fp) != NULL) { 
     ++lnum; 
     if (sscanf(buffer, "%200[^$]$$$%d", title, &price) == 2) { 
      printf("Title: %s --- Price: $%d\n", title, price); 
     } else { 
      fprintf(stderr, "Format error in line %zu\n", lnum); 
     } 
    } 

    fclose(fp); 

    return 0; 
} 

fgets()の使用は、入力の検査で、より柔軟に行うことができます。 $がタイトルの一部である場合を処理するには、strstr()を使用して最初に区切り文字" $$$"を見つけて、区切り文字までの文字をループ内のtitle[]アレイにコピーします。 strstr()は見つかった文字列へのポインタを返すので、このポインタはsscanf()に渡され、最後の数字が取り出されます。 strstr()関数は、文字列が見つからない場合はnullポインタを返し、これを使用して書式の問題がある行を識別できます。ここ

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define BUF_SZ  1000 
#define MAX_TITLE 201 

int main(void) 
{ 
    /* Open file, and check for success */ 
    FILE *fp = fopen("data.txt", "r"); 
    if (fp == NULL) { 
     perror("Unable to open file"); 
     exit(EXIT_FAILURE); 
    } 

    char buffer[BUF_SZ]; 
    char title[MAX_TITLE]; 
    int copies; 
    size_t lnum = 0; 

    while (fgets(buffer, BUF_SZ, fp) != NULL) { 
     ++lnum; 

     /* Find delimiter string in buffer */ 
     char *title_end = strstr(buffer, " $$$"); 
     if (title_end == NULL) { 
      fprintf(stderr, "Format error in line %zu\n", lnum); 
      continue; 
     } else { 

      /* Copy characters into title until space before delimiter */ 
      char *curr = buffer; 
      size_t i = 0; 
      while (curr < title_end && i < MAX_TITLE) { 
       title[i] = buffer[i]; 
       ++curr; 
       ++i; 
      } 
      title[i] = '\0'; 
     } 

     if (sscanf(title_end, " $$$%d", &copies) == 1) { 
      printf("Title: %s --- Copies: %d\n", title, copies); 
     } else { 
      fprintf(stderr, "Format error in line %zu\n", lnum); 
     } 
    } 

    fclose(fp); 

    return 0; 

}

は、修正された入力ファイルである:

The Cheit and its Punishment $$$ 8 
War and Remembrance $$$ 12 
Winds of War $$$ 12 
A million $ exit $$$ 16 
How to Play Football $$$ 12 
Ultrashort Pulses $$$ 8 
Nonlinear Optics $$$ 8 

得られた出力:

Title: The Cheit and its Punishment --- Copies: 8 
Title: War and Remembrance --- Copies: 12 
Title: Winds of War --- Copies: 12 
Title: A million $ exit --- Copies: 16 
Title: How to Play Football --- Copies: 12 
Title: Ultrashort Pulses --- Copies: 8 
Title: Nonlinear Optics --- Copies: 8 
+0

私が今までに得た最も包括的な説明。今までのところ成功しなかったfgetsとstrtokを使用しようとしていました。 "%200 [^ $] $$$%d"入力も機能するsscanfを使用していますか?それはどのように見えますか? –

+0

フレーズがメインの質問に対処する新しい「バグ」を追加しました。アイデアがありますか? –

+0

@ OriAshkenazi--最後の編集で追加した問題を誤解していました...回答が更新されました。 –

0

これはあなたが何ができるかのアイデアを与える必要があります。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main() 
{ 
    char line[] = "The Cheit and its Punishment $$$ 8"; 

    char *seppointer = strchr(line, '$'); 
    *seppointer = 0;  
    int price = atoi(seppointer + 4); 

    printf("Title: %s\nPrice: %d\n", line, price); 
} 

免責事項を:そこにはエラーチェックがありません、ラインを持っていると仮定されます必要なフォーマット。

+0

私は混乱していました。 "* ptr"呼び出しはポインタの "内容"にどうやって到達するのか、私は最後の質問 –

+0

を削除したのですが、これは私のコードで実装するのに本当に役に立つアイディアでした。 –

+0

@OriAshkenaziは答えを受け入れるか、それをアップビューしても構いません。 –