1
votes

My question is if would be possible to ignore a specific part of a txt file later stored in a struct using fscanf(). For the purpose of the example let me say I have a txt file made out of this text:

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

And I want to store the data in a struct like this one ignoring the words Title:, Author:, Publication year: and so on:

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

This is the code I have implemented in order to store the data:

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
...

HERE A MINIMAL EXAMPLE:

#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;
}

It is possible or not to do so?

3
do you want to ignore the words before the colon?DevUt
I want to ignore the words "Title:/Author:" and so onpanini
Which would be before the colon surely right?DevUt
Your problem is unrelated to structs and files. The solution is the same if you just want to read from keyboard into a simple array.klutt
Did you understand what I want to do? By the way English isn't my first language too so maybe the problem is that I am unable to explain myself.panini

3 Answers

0
votes

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

Without using fscanf

You can just use strchr() function.

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

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

There are ways to use format strings for this. That's a perfectly viable option. But the simplest way is probably something like this:

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

Have not test the code above. Might be minor mistakes.

0
votes

The problem with your question is that you failed to clearly define what you want your program to do.

First of all you should clearly state your objective. Given this file:

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

it should read "C Programming Language" and "Dennis Ritchie", then the rest. But is the space after "Title:" mandatory? Can there be more than one space? Can you have "empty" lines between Title and Author? Is it mandatory to have "Title: "? Can "Author" be before "Title"? And so on... After you define all this you have a file format and maybe you can parse it with fscanf.

In this case, if the format is

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

you can parse it with:

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

This requires the presence of the characters Title: before the title itself. It will fail if those are missing.

Then since your buffer is limited in size (a very bad idea) it is recommended to limit the maximum number of characters that fscanf() will try to put in your variable (I'm assuming you have an array of 31 characters):

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

Doing it with macros is a pain, but it can be done. So you could read that file like this:

#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;
}

Well, maybe it's better to sprintf() to a format variable and do use that as format string, but I'm not a fan of any of the two solutions. The best thing is probably to use something like POSIX getline()