2017-06-15 33 views
-2

據我瞭解字符串的長度,還有解析的方式輸入這樣的:如何使用的fscanf不知道在每一行

一億$出口$$$ 16
的Cheit及其處罰$$$ 8
的戰爭和記憶$$$ 12個
風戰爭$$$ 12
如何玩足球$$$ 12個
超短脈衝 8個$$$
非線性光學$$$ 8
等。

「$$$」在數據字段之間分開。
我期待升級了一句:

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

所以它會適合線上沒有。 1在這個例子中。

編輯:

#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

通常的方法是使用'fgets'將整行讀入合適的大緩衝區,然後使用'sscanf' /'strtok'/whatever解析它。 –

+2

你試過了嗎?你有代碼要呈現嗎? – Gam

+1

你有*最大*行長嗎?我不確定'fscanf'(和家庭)在這裏可能是正確的選擇......相反,我可能會用'fgets'和'strstr'做一些事情。 –

回答

0

如果您知道最長的標題爲200個字符,如your comment中所示,您可以爲此分配一個數組(包括空終止符的空格)。

您可以使用fscanf()解析格式字符串爲" %200[^$]$$$%d"的文件的行。第一個空格告訴fscanf()跳過前面的I/O操作可能留下的空白空間。下一個轉換指定器是%200[^$],它告訴fscanf()將任何字符讀入字符串,直到遇到$$保留在輸入流中。請注意,此處指定的最大寬度爲200,以防止緩衝區溢出。格式字符串中的下三個字符$$$必須存在於輸入中,並且在達到最終轉換說明符%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()之前添加代碼以清除輸入流。

該方法的一個優點是,由於包括\n在內的整行被讀取,因此不需要像以前那樣跳過前導空白字符。另一個優點是,最終號碼後的虛假字符可以忽略,或由代碼處理;由於線被存儲,因此可以根據需要多次檢查和掃描線。最後一個數字後面的字符會導致第一個版本出現問題,而第一個版本僅適用於跳過主要空格。

#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()函數將返回空指針,並且這可以用於標識具有格式問題的行。需要注意的是strstr()是在string.h

#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迄今沒有成功。使用sscanf與「%200 [^ $] $$$%d」輸入將工作?它應該是什麼樣子? –

+0

增加了一個新的「bug」這個短語應該處理的主要問題,有什麼想法? –

+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

和thx再次,這是一個非常有用的想法,我在我的代碼中實現。 –

+0

@OriAshkenazi可以隨時接受答案和/或upvote它。 –