2

可能重复:
C,从文件读入结构

我需要阅读一个大文本文件,然后为邮件列表填充数据结构。

数据结构如下:

typedef struct mentry {
    char *surname;
    int house_number;
    char *postcode;
    char *full_address;
} MEntry;

文本文件格式为:

Bloggs, Joe  
1 Street Name, City  
M53 3JK  
Surname, Firstname  
University of Nowhere, City  
G44 3GB

等等

我的数据结构构造函数:

/* me_get returns the next file entry, or NULL if end of file*/
MEntry *me_get(FILE *fd);

它返回一个指向包含邮件列表条目的 MEntry 结构的指针。

到目前为止,我只设法逐行读取文件。

#define MAXLINE 1024

int main(){
    char line[MAXLINE];
    FILE *fp = fopen("S.txt","r");

    while(fgets(line,MAXLINE,fp))
        {
        printf("%s %d",line,linecount);
    }

    fclose(fp);
    return 0;
}

我目前的主要问题是我不知道如何分割我的行以便我可以正确地填充我的数据结构。我想知道使用 fgetc 一次读取一个字符是否比读取整行然后尝试拆分它更容易?

4

3 回答 3

2

可能你应该使用strtok

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

int main ()
{
    char str[] ="Elizarraras, Salvador, UG";
    char *token = NULL;
    int n_tokens = 0;

    printf ("Get tokens from string \"%s\"\n",str);
    printf("%s\n", "*********************************************");

   // Split the string into tokens delimited by spaces and commas
   token = strtok (str," ,");
   while (token != NULL)
   {
       printf("%s\n", token);
       // Different call
       token = strtok (NULL, " ,");
       n_tokens++;
   }

  return 0;
}

输出:

Get tokens from string "Elizarraras, Salvador, UG"

*********************************************
Elizarraras

Salvador

UG

有一篇关于这个主题的有趣文章,Finding Tokens in a String

于 2012-10-18T15:54:26.943 回答
0

在您的示例中,第二个地址没有任何house_number.

这意味着您不能依赖数据格式来盲目地读取文件。

你别无选择,只能读取数据然后解析它。

如果地址在指定之前有 2 行文本,则可能会发生其他问题postcode

你是唯一知道你的输入文件有多可靠的人,因此必须应用什么规则来解析它而不会出错。

关于该方法,我将逐行读取文件并通过解析每一行文本来即时解释它,直到postcode找到每条记录(因为这似乎是您的记录结束标记)。

解析意味着在line[]阅读时查看字符并对数据进行分类(即:逗号是名字/姓氏的分隔符,街道号码是数字,邮政编码遵循某种格式等)。

这将需要一些工作,但这是可行的。根据口味,您知道我不会冒险涉足 RegEx 领域(而 C 有一个专用的运行时库)。

祝你好运!

于 2012-10-18T15:54:04.873 回答
0

我会这样做:

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

// It is easyer for the memory allocator to have all in the struct
// It is a bit more wasteful on memory though if you set those too large
#define MAX_SURNAME_LENGTH 32
#define MAX_POSTCODE_LENGTH 32
#define MAX_FULL_ADDRESS_LENGTH (256 - MAX_SURNAME_LENGTH - MAX_POSTCODE_LENGTH - sizeof(int))

typedef struct mentry {
    char surname[MAX_SURNAME_LENGTH];
    char postcode[MAX_POSTCODE_LENGTH];
    int house_number;
    char full_address[MAX_FULL_ADDRESS_LENGTH];
} MEntry;

MEntry *me_get(FILE *fp) {
    MEntry *mentry = calloc(sizeof(MEntry), 1);

    // get name
    char * name = fgets(mentry->surname, sizeof(mentry->surname), fp);
    if (!name) { //failure
        free(mentry);
        return NULL;
    }

    char * comma = strchr(name, ','); // find the first comma appearance
    if (comma) *comma = '\0'; // If name has a comma in it, terminate the string there

    char * address = fgets(mentry->full_address, sizeof(mentry->full_address), fp);
    if (!address) { //failure
        free(mentry);
        return NULL;
    }

    char * restaddress;
    int housenumber = strtol(address, &restaddress, 10);

    if (restaddress != address) // there was a valid number at the start of address
        mentry->house_number = housenumber;

    char * postcode = fgets(mentry->postcode, sizeof(mentry->postcode), fp);
    if (!postcode) { //failure
        free(mentry);
        return NULL;
    }

    return mentry;
}

int main() {
    FILE *fp = fopen("S.txt","r");

    MEntry *mentry;
    while ((mentry = me_get(fp))) {
        // do something useful with mentry
    }

    fclose(fp);
    return 0;
}
于 2012-10-18T16:40:03.597 回答