destroted
destroted

Reputation: 79

Parsing in .txt file in C

I am trying to parse a .txt in C, then return the values to a struct. The .txt file im trying to parse is

2X6 de8 dw3 ds5 g8,7 m3,4 p2,2 h2,2
8X22 de8 dw3 ds5 g8,7 m3,4 p2,2 h2,4
12X6 de8 dw3 ds5 g8,7 m3,4 p2,2 h2,6
12X6 de8 dw3 ds5 g8,7 m3,4 p2,2 h2,10
12X6 de8 dw3 ds5 g8,7 m3,4 p2,2 h2,12
12X15 de8 dw3 ds5 g8,7 m3,4 p2,2 h2,14

The way i have my code right now, i can parse through everything except for the first element e.g . "2X6" or "8X22". In my code i read through a line from the .txt file using fgets and then i go through each element using strtok. I was wondering how i would go about parsing through that first element and setting the numbers to be equal to variables which i will later send to a struct

my code is:

void parser(int argc, char **argv)
{
FILE * rooms;
char * theString;
char * theToken;
int numberElements;
int side;
int k;
int x;
int placeInt;
int posX;
int posY;
char a[ROOM_STRING_LENGTH];
struct item gold;
struct item monster;
struct item potion;
struct item hero;
struct room roomInfo;
numberElements = 0;
rooms = fopen(argv[1], "r");

if(rooms == NULL)
{
    printf("error opening file\n");
}
x = 0;
while(fgets(a, ROOM_STRING_LENGTH, rooms) != NULL)
{ 
    theString = malloc((sizeof(char)*(strlen(a)+1)));
    strcpy(theString, a);

    for(theToken = strtok(theString, " "); theToken; theToken = strtok(NULL, " "))
    {
        printf("the next token: %s\n", theToken);

        if(theToken[0] == 'd')
        {
            switch(theToken[1])
            {
                case 'e':
                {
                    placeInt = theToken[2] - '0';
                    printf("the side: %d, the place: %d\n", side, placeInt);
                    break;
                }
                case 'w':
                {
                    side = 2;
                    placeInt = theToken[2] - '0';
                    printf("the side: %d, the place: %d\n", side, placeInt);
                    break;
                }
                case 's':
                {
                    side = 3;
                    placeInt = theToken[2] - '0';
                    printf("the side: %d, the place: %d\n", side, placeInt);
                    break;
                }
                case 'n':
                {
                    side = 4;
                    placeInt = theToken[2] - '0';
                    printf("the side: %d, the place: %d\n", side, placeInt);
                    break;
                }
                default:
                {
                    break;
                } 
            }       
        }

        else if(theToken[0] == 'g' || theToken[0] == 'm' || theToken[0] == 'p' || theToken[0] == 'h')
        {
             k = 0;
             while(k <= (strlen(theToken)))
             {

                 switch(theToken[k])
                 {
                     case 'g':
                     posY = theToken[1] - '0';
                     posX = theToken[3] - '0';

                     gold.Xposition = posX;
                     gold.Yposition = posY;
                     printf("the y position: %d, the x position: %d\n",  posY, posX);
                     break;

                     case 'm':
                     posY = theToken[1] - '0';
                     posX = theToken[3] - '0';

                     monster.Xposition = posX;
                     monster.Yposition = posY;
                     printf("the y position: %d, the x position: %d\n",  posY, posX);
                     break;

                     case 'p':
                     posY = theToken[1] - '0';
                     posX = theToken[3] - '0';

                     potion.Xposition = posX;
                     potion.Yposition = posY;
                     printf("the y position: %d, the x position: %d\n",  posY, posX);
                     break;

                     case 'h':
                     posY = theToken[1] - '0';
                     posX = theToken[3] - '0';

                     hero.Xposition = posX;
                     hero.Yposition = posY;
                     printf("the y position: %d, the x position: %d\n", posY, posX);                         
                     break;
                 }
                 k++;
             }
        }
        else if(theToken == NULL)
        {
            printf("end of file");
        }
        numberElements++;
    }

    if(theToken == NULL)
    {
        printf("You've reached the end of the line\n");
    }
    printf("%d\n", numberElements);
    x++;
}

free(theString);
fclose(rooms);
 }

Upvotes: 0

Views: 151

Answers (2)

pmg
pmg

Reputation: 108978

Your problem is in the successive ifs

    for(theToken = strtok(theString, " "); theToken; theToken = strtok(NULL, " "))
    {
        if(theToken[0] == 'd')
        {
            /* ... */
        }
        else if(theToken[0] == 'g' || theToken[0] == 'm' || theToken[0] == 'p' || theToken[0] == 'h')
        {
            /* ... */
        }
        else if(theToken == NULL)
        {
            /* ... */
        }
    }

Notice that when theToken points to a string beginning with something other than 'd', 'g', 'm', 'p', or 'h' no code will be executed in the body of the for loop (except the initial printf() and the final increment to numberElements).

Upvotes: 0

M Oehm
M Oehm

Reputation: 29126

Two quick notes about your code: With expressions like theToken[2] - '0' you can hanlde only single-digit numbers (unless you encode 12, say as '<'). Your last input line in the example file won't work.

Also, if you allocate a temporary string inside the loop, you should also free it inside the loop. Otherwise, only the last allocated string will be freed. In your case, you don't really need the string copy, because you are already working with a mutable charachter buffer read from a file that you can tokenise with strtok.

To your problem at hand: You can use strtok and then go at the tokens with sscanf. Here's a short example code that deals only with some of your formats. The first token must be the dungeon dimension, the following tokens must begin with a command letter.

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

void aaargh(const char *msg)
{
    fprintf(stderr, "Aaargh: %s\n", msg);
    exit(1);
}

int dir(int c) {
    if (c == 'e') return 1;
    if (c == 'w') return 2;
    if (c == 's') return 3;
    if (c == 'n') return 4;
    return 0;
}

int main(int argc, char **argv)
{
    char line[] = "12X15 de8 dw3 ds5 m3,4,orc m10,8,troll m6,13,medusa";
    char *tk;

    int width, height;

    tk = strtok(line, " ");
    if (sscanf(tk, "%dX%d", &width, &height) < 2) {
        aaargh("Illegal dimension.");
    }

    printf("Dungeon size: %d x %d\n", width, height);

    tk = strtok(NULL, " ");
    while (tk) {
        switch (tk[0]) {
        case 'd': {
                int side = dir(tk[1]);
                int pos;

                if (side == 0) aaargh("Illegal side");

                if (sscanf(tk + 2, "%d", &pos) < 1) {
                    aaargh("Illegal pos");
                }
                printf("Wall side %d, pos %dn\n", side, pos);
            }
            break;

        case 'm': {
                int x, y;
                char which[20];

                if (sscanf(tk, "m%d,%d,%19s", &x, &y, which) < 1) {
                    aaargh("Illegal monster description");
                }
                printf("Monster: %s at %d, %d\n", which, x, y);

            }
            break;

        default:
            aaargh("Unknown command");
        }

        tk = strtok(NULL, " ");        
    }

    return 0;
}

Error tracking is very rudimentary and should really tell what went wrong where, so you can catch input errors.

Upvotes: 1

Related Questions