在C中解析.txt文件

时间:2014-03-14 06:48:37

标签: c parsing

我试图在C中解析.txt,然后将值返回到结构。 我试图解析的.txt文件是

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

我现在拥有代码的方式,我可以解析除第一个元素之外的所有内容 例如" 2X6"或" 8X22"。在我的代码中,我使用fgets读取.txt文件中的一行,然后使用strtok遍历每个元素。我想知道如何解析第一个元素并将数字设置为等于我稍后将发送给结构的变量

我的代码是:

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

2 个答案:

答案 0 :(得分:1)

关于你的代码的两个快速注释:对于像theToken[2] - '0'这样的表达式,你只能使用一位数字(除非你编码12,比如说'&lt;')。您示例文件中的最后一个输入行将不起作用。

此外,如果在循环内部分配临时字符串,则还应将其释放到循环内。否则,只释放最后分配的字符串。在您的情况下,您实际上并不需要字符串副本,因为您已经在使用可以使用strtok标记的文件读取可变charachter缓冲区。

解决您的问题:您可以使用strtok,然后使用sscanf转到令牌。这是一个简短的示例代码,仅处理您的某些格式。第一个标记必须是地牢维度,以下标记必须以命令字母开头。

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

错误跟踪非常简陋,应该真正告诉错误在哪里,这样你就可以捕获输入错误。

答案 1 :(得分:0)

您的问题出在后续if s

    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)
        {
            /* ... */
        }
    }

请注意,当theToken指向以'd''g''m''p''h'以外的字符串开头的字符串时没有代码将在for循环体中执行(初始printf()除外,最后一个增量为numberElements)。