Home > front end >  C: Combining `sscanf` specifiers to read upto a number of characters
C: Combining `sscanf` specifiers to read upto a number of characters

Time:03-11

I need to read lines of strings in a text file that represent movie showings and format them. I need to use sscanf to scan the string saved by fgets. My problem is how do I make sscanf only read upto x amount of characters while also using [^] specifier. Movie title lengths have a max length of 44. I know C has %0.*s but I need to use it in combination with [^]. I tried doing %0.44[^,] but to no avail. My code is below. I have commented out what I though would be the solution.

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

int main(void) {
    const int MAX_TITLE_CHARS = 44;  // Maximum length of movie titles
    const int LINE_LIMIT = 100;   // Maximum length of each line in the text file
    char line[LINE_LIMIT];
    char inputFileName[25];


    FILE *file;
    file = fopen("D:\\movies.csv", "r");

    char currentLine[LINE_LIMIT];
    char movieTitle[MAX_TITLE_CHARS];
    char movieTime[5];
    char movieRating[5];

    fgets(currentLine, LINE_LIMIT, file);
    while(!feof(file)){
        
    //  sscanf(currentLine, "%[^,],%0.44[^,],%[^,]", movieTime, movieTitle, movieRating);
        sscanf(currentLine, "%[^,],%[^,],%[^,]", movieTime, movieTitle, movieRating);

        printf("%-44s |\n", movieTitle);
        fgets(currentLine, LINE_LIMIT, file);
    }


    return 0;
}

This prints out the following

Wonders of the World                         |
Wonders of the World                         |
Journey to Space                             |
Buffalo Bill And The Indians or Sitting Bull's History Lesson |
Buffalo Bill And The Indians or Sitting Bull's History Lesson |
Buffalo Bill And The Indians or Sitting Bull's History Lesson |
Adventure of Lewis and Clark                 |
Adventure of Lewis and Clark                 |
Halloween                                    |

I need to it be

Wonders of the World                         |
Wonders of the World                         |
Journey to Space                             |
Buffalo Bill And The Indians or Sitting Bull |
Buffalo Bill And The Indians or Sitting Bull |
Buffalo Bill And The Indians or Sitting Bull |
Adventure of Lewis and Clark                 |
Adventure of Lewis and Clark                 |
Halloween                                    |

CodePudding user response:

sscanf(currentLine, "%[^,],C[^,],%[^,]", movieTime, movieTitle, movieRating);

Where 43 is the amount of chars to read and one left for a null terminator. I assume the compiler was unhappy about the 0. complaining about zero width and unknown conversion type.

CodePudding user response:

I know C has %0.*s

No, it does not. For sscanf, the way to limit the number of characters accepted is to give the width as a decimal numeral after the %, without 0 or ., as in "%3s". It must be an actual numeral; it cannot be * as in printf, which specifies that the number is passed as an argument.

To use this with the [ conversion specifier, you would use "D[^,]".

If the maximum move title length is 44 characters, then the array that holds them as a string should be declared as char movieTitle[MAX_TITLE_CHARS 1]; to allow for a terminating null character.

If you want to parameterize the sscanf string based on the symbol MAX_TITLE_CHARS, so that it adapts if the value is changed, you can do this by defining MAX_TITLE_CHARS as a macro instead of a const int object:

#define MAX_TITLE_CHARS 44

and defining macros to convert a parameter into a string:

//  Two macros are needed due to the order of operations in macro replacement.
#define ExpandAndStringize(x)   #x
#define Stringize(x)            ExpandAndStringize(x)

and using them:

sscanf(currentline,"%[^,],%" Stringize(MAX_TITLE_CHARS) "[^,],%[^,]", movieTime, movieTitle, movieRating);
  • Related