【问题标题】:How to ignore a specific part of txt file in C如何在C中忽略txt文件的特定部分
【发布时间】:2021-04-01 03:02:36
【问题描述】:

我的问题是是否可以忽略稍后使用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;
}

有没有可能?

【问题讨论】:

  • 要忽略冒号前的单词吗?
  • 我想忽略“Title:/Author:”等字样
  • 冒号前面肯定是对的?
  • 您的问题与结构和文件无关。如果您只想从键盘读取到一个简单的数组,解决方案是相同的。
  • 你明白我想做什么了吗?顺便说一句,英语也不是我的第一语言,所以问题可能是我无法解释自己。

标签: c file struct txt


【解决方案1】:

使用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()函数。

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

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

【讨论】:

    【解决方案2】:

    有一些方法可以为此使用格式字符串。这是一个完全可行的选择。但最简单的方法大概是这样的:

    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);
    

    没有测试上面的代码。可能是小错误。

    【讨论】:

    • 它不起作用。 newOne->books.tile[size] 在编译器中被视为一个指针,它需要强制转换
    【解决方案3】:

    你的问题的问题是你没有清楚地定义你想让你的程序做什么。

    首先,您应该明确说明您的目标。鉴于此文件:

    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”,然后是其余的。但是“标题:”后面的空格是强制性的吗?可以有多个空间吗?标题和作者之间可以有“空”行吗?是否必须具有“标题:”? “作者”可以在“标题”之前吗?等等……在你定义了所有这些之后,你就有了一个文件格式,也许你可以用 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()

    【讨论】:

      猜你喜欢
      • 2020-11-05
      • 2019-11-16
      • 1970-01-01
      • 1970-01-01
      • 2013-10-02
      • 2022-11-22
      • 2020-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多