我的目标是逐行读取文本文件,然后将每一行划分为不同的变量。我尝试使用fgets,并成功地将其存储到链接列表中。但它存储了整行,相反,我只希望它存储到分号。例如,第一行是:
1;IMG_3249.JPG;730x1114;158KB;Hamburg;Germany;16/03/2020 09:12
在这里,我希望"1"存储在id中,"IMG_3249"存储在名称中。事情是这样的。到目前为止,我做到了;
struct list {
char *string;
int id;
char *name;
char *dim;
char *size;
char *location;
char *date;
struct list *next;
};
typedef struct list LIST;
int main ()
{
FILE *fp;
char line[110];
LIST *current, *head;
head = current = NULL;
fp = fopen("PhotoInfoBook.txt", "r");
while(fgets(line, sizeof(line), fp)){
LIST *node = malloc(sizeof(LIST));
node->string = strdup(line);
node->next =NULL;
if(head == NULL){
current = head = node;
} else {
current = current->next = node;
}
}
fclose(fp);
}
关于我该怎么做有什么想法吗?
您可以将对strdup(line)
的调用替换为对自己函数的调用,该函数将找到给定行中的第一个分号,分配一个适当长度的字符串,并将输入行中直到第一个分号的所有字符复制到输出字符串中。
例如:
char* my_strdup(const char* line)
{
int len;
for (len = 0; line[len] != ';' && line[len] != 0; len++) { }
char* new_line = malloc(len + 1);
for (int i = 0; i < len; i++)
new_line[i] = line[i];
new_line[len] = 0;
return new_line;
}
我并不特别喜欢strtok
,因为如果修改传递的字符串,它不是线程安全的,但这是一个正确的用例。事实上,它用null替换了分隔符(这里是分号;
(,并允许在传递的字符串中有指针。这是一个很好的想法,因为strdup
分配了整个字符串。你可以做:
while(fgets(line, sizeof(line), fp)){
LIST *node = malloc(sizeof(LIST));
node->string = strdup(line);
node->name = strtok(node->string, ';');
// if (node->name == NULL) error processing
node->id = atoi(node->string); // ok the firt ; is now a null
node->dim = strtok(NULL, ';');
...
node->date = (strtok(NULL, ';');
node->next =NULL;
为简便起见,省略了错误处理。。。
有几个函数使C中的这种处理更容易、更安全。阅读getline、regexec和strndup的手册页。另一个建议是使用约定,即链接列表中的最后一项是标记列表末尾的哨兵。它简化了列表的管理。
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list_t {
char *string;
int id;
char *name;
char *dim;
char *size;
char *location;
char *date;
struct list_t *next;
} list_t;
int main(int argc, char* argv[])
{
FILE *fp = fopen("PhotoInfoBook.txt", "r");
char *line = NULL;
size_t capacity = 0;
list_t *head = calloc(1, sizeof(list_t));
list_t *iter = head;
regex_t re;
regcomp(&re, "([0-9]+);([^;]+);([^;]+);([^;]+);([^;]+);([^;]+)", REG_EXTENDED);
regmatch_t capture[7];
while (getline(&line, &capacity, fp) > 0) {
if (regexec(&re, line, 7, capture, 0) == 0) {
iter->string = strdup(line);
iter->id = strtoul(line, NULL, 10);
iter->name = strndup(&line[capture[2].rm_so], capture[2].rm_eo - capture[2].rm_so + 1);
iter->dim = strndup(&line[capture[3].rm_so], capture[3].rm_eo - capture[3].rm_so + 1);
iter->size = strndup(&line[capture[4].rm_so], capture[4].rm_eo - capture[4].rm_so + 1);
iter->location = strndup(&line[capture[5].rm_so], capture[5].rm_eo - capture[5].rm_so + 1);
iter->date = strndup(&line[capture[6].rm_so], capture[6].rm_eo - capture[6].rm_so + 1);
iter->next = calloc(1, sizeof(list_t));
iter = iter->next;
}
}
for (iter = head; iter->next != NULL; iter = iter->next) {
printf( "line : %s", iter->string);
printf( " id: %dn", iter->id);
printf( " name: %sn", iter->name);
printf( " dim: %sn", iter->dim);
printf( " size: %sn", iter->size);
printf( " location: %sn", iter->location);
printf( " date: %sn", iter->date);
}
return 0;
}