[英]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.