1

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?

panini
  • 13
  • 8

3 Answers3

0

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
Krishna Kanth Yenumula
  • 2,533
  • 2
  • 14
  • 26
0

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.

klutt
  • 30,332
  • 17
  • 55
  • 95
  • It does not work. newOne->books.tile[size] is seen from the compiler as a pointer and it wants the cast – panini Dec 22 '20 at 12:27
0

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

Costantino Grana
  • 3,132
  • 1
  • 15
  • 35