簡體   English   中英

C中如何忽略txt文件的特定部分

[英]How to ignore a specific part of txt file in C

我的問題是是否可以忽略稍后使用fscanf()存儲在結構中的 txt 文件的特定部分。 出於示例的目的,我假設我有一個由以下文本組成的 txt 文件:

Title: C Programming Language
Author: Dennis Ritchie
Publication year: 1978
...

我想將數據存儲在像這樣的結構中,忽略Title:Author:Publication year:等等:

struct book {
    char title[MAX];
    char author[MAX];
    int pubblication_year;
    ...
};

這是我為存儲數據而實現的代碼:

fscanf(fp, "%[^\n]%*c\n", newOne->books.title);  //titolo
fscanf(fp, "%[^\n]%*c\n", newOne->books.author); //autore
fscanf(fp, "%d\n", &newOne->books.pubblication_year); //anno pubblicazione
...

這是一個最小的例子:

#include <stdio.h>
#include <stdlib.h>
#define MAX 30
struct book {
    char title[MAX];
    char author[MAX];
};

struct booklist {
    struct book books;
    struct booklist *next;
};


int main() {
    struct booklist *head = NULL, *newOne, *temp; //temp made in order to clear the heap once the program is termined
    FILE *fp;
    fp = fopen("FileName.txt", "r");
    if(fp == NULL) {
    printf("Something wrong happened, the program will close!\n");
        system("pause");
        exit(1);
    } else {
        newOne = (struct booklist *)malloc(sizeof(struct booklist));
        if(newOne == NULL) {
            printf("Error, not enough space to store the new book, the program will close!\n");
                   system("Pause");
                   exit(1);
        }
        fscanf(fp, "%[^\n]%*c\n", newOne->books.title);  //ADDING THE TITLE TO THE NODE
        fscanf(fp, "%[^\n]%*c\n", newOne->books.author); //SAME FOR THE AUTHOR

        //adding the new one node created to the head of the list
        newOne->next = head;
        head = newOne;
    }
    while (newOne != NULL) { //cleaning the heap once the program is termined
    temp = newOne;
    newOne = newOne -> next;
    free(temp);
    }
    fclose(fp);
    return 0;
}

是否可以這樣做?

使用fscanf

char str[] = "Title: C Programming Language";
int len1 = strlen(str); // find length of str

char ch = ':';
char *ret;

ret = strchr(str, ch); // ret points to ---> : C Programming Language
int len2 = strlen(ret);

fseek(fp, (len1-len2), SEEK_SET); // move file pointer
fscanf(fp, "%[^\n]%*c", newOne->books.title);

不使用fscanf

你可以只使用strchr() function。

char str[] = "Title: C Programming Language";
char ch = ':';
char *ret;

ret = strchr(str, ch); 
printf("%s", ret+1) // prints C Programming Language

有一些方法可以為此使用格式字符串。 這是一個完全可行的選擇。 但最簡單的方法可能是這樣的:

fscanf(fp, "%[^\n]%*c\n", newOne->books.title);
char remove[] = "Title: ";
size_t size = sizeof (remove);
char *s = newOne->books.title;
memove(s, s[size], size);

沒有測試上面的代碼。 可能是小錯誤。

您的問題的問題在於您未能明確定義您希望程序執行的操作。

首先你應該清楚state你的目標。 鑒於此文件:

Title: C Programming Language
Author: Dennis Ritchie

Title: The Lord of the Rings
Author: John Ronald Reuel Tolkien

Title: War and Peace
Author: Leo Tolstoy

它應該讀作“C Programming Language”和“Dennis Ritchie”,然后是 rest。但是“Title:”之后的空格是強制性的嗎? 可以有多個空間嗎? 標題和作者之間可以有“空”行嗎? 是否必須具有“標題:”? “作者”可以在“標題”之前嗎? 等等......在你定義了所有這些之后,你就有了一個文件格式,也許你可以用 fscanf 解析它。

在這種情況下,如果格式是

<0 or more whitespaces> Title: <0 or more whitespaces> <anything but newline> <newline>

你可以解析它:

fscanf(fp, " Title: %[^\n]", /*...*/);

需要在標題本身之前出現字符Title: :。 如果缺少這些,它將失敗。

然后,由於您的緩沖區大小有限(一個非常糟糕的主意),建議限制fscanf()將嘗試放入您的變量的最大字符數(我假設您有一個 31 個字符的數組):

fscanf(fp, " Title: %30[^\n]", tmp->books.title);

用宏做這件事很痛苦,但可以做到。 所以你可以像這樣閱讀那個文件:

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

#define xstr(s) str(s)
#define str(s) #s

#define MAX 30
struct book {
    char title[MAX + 1];
    char author[MAX + 1];
};

struct booklist {
    struct book books;
    struct booklist *next;
};
struct booklist *new_booklist(void)
{
    struct booklist *newOne = malloc(sizeof(struct booklist));
    if (newOne == NULL) {
        printf("Error, not enough space to store the new book, the program will close!\n");
        exit(1);
    }
    return newOne;
}
void booklist_add(struct booklist **head, struct booklist *newOne)
{
    newOne->next = *head;
    *head = newOne;
}
void booklist_delete_list(struct booklist **head)
{
    struct booklist *cur = *head;
    while (cur != NULL) {
        struct booklist *temp = cur;
        cur = cur->next;
        free(temp);
    }
    *head = NULL;
}

int main(void)
{
    struct booklist *head = NULL; 
    
    FILE *fp = fopen("input.txt", "r");
    if (fp == NULL) {
        printf("Something wrong happened, the program will close!\n");
        exit(1);
    }

    while(1) {
        struct booklist *tmp = new_booklist();

        int n = 0;
        n += fscanf(fp, " Title: %" xstr(MAX) "[^\n]", tmp->books.title);
        n += fscanf(fp, " Author: %" xstr(MAX) "[^\n]", tmp->books.author);

        if (n != 2) {
            free(tmp);
            break;
        }

        booklist_add(&head, tmp);
    }

    booklist_delete_list(&head);

    fclose(fp);
    return 0;
}

好吧,也許將sprintf()轉換為格式變量並將其用作格式字符串會更好,但我不喜歡這兩種解決方案中的任何一種。 最好的辦法可能是使用像 POSIX getline()這樣的東西

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM