我的作业遇到了问题。我需要将一些数据从文本文件扫描到结构。 文本文件如下所示。
012345678;danny;cohen;22;M;danny1993;123;1,2,4,8;Nice person
223325222;or;dan;25;M;ordan10;1234;3,5,6,7;Singer and dancer
203484758;shani;israel;25;F;shaninush;12345;4,5,6,7;Happy and cool girl
349950234;nadav;cohen;50;M;nd50;nadav;3,6,7,8;Engineer very smart
345656974;oshrit;hasson;30;F;osh321;111;3,4,5,7;Layer and a painter
每个数据项都与其匹配变量匹配。 id = 012345678 first_name =丹尼 等等...
现在我不能使用fscanf,因为没有间距,并且fget会扫描所有行。
我找到了%[^;] s的一些解决方案,但随后我将需要编写一个代码块,并为每一项数据复制并粘贴9次。
如果每一项数据之间都有间隔,是否还有其他选项不更改文本文件,类似于我用fscanf编写的代码?
*************更新**************
嘿,首先,感谢大家的帮助。 我听不懂您的回答,但这里确实使用了一些东西。
这是我的代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *idP, *firstNameP, *lastNameP;
int age;
char gender, *userNameP, *passwordP, hobbies, *descriptionP;
}user;
void main() {
FILE *fileP;
user temp;
char test[99];
temp.idP = (char *)malloc(99);
temp.firstNameP = (char *)malloc(99);
temp.lastNameP = (char *)malloc(99);
temp.age = (int )malloc(4);
temp.gender = (char )malloc(sizeof(char));
temp.userNameP = (char *)malloc(99);
fileP = fopen("input.txt", "r");
fscanf(fileP, "%9[^;];%99[^;];%99[^;];%d;%c", temp.idP,temp.firstNameP,temp.lastNameP,&temp.age, temp.gender);
printf("%s\n%s\n%s\n%d\n%c", temp.idP, temp.firstNameP, temp.lastNameP, temp.age, temp.gender);
fgets(test, 60, fileP); // Just testing where it stop scanning
printf("\n\n%s", test);
fclose(fileP);
getchar();
}
一切正常,直到我扫描了int变量,此后它什么也不扫描,并且出现了错误。
非常感谢。
答案 0 :(得分:2)
如评论中所述,fscanf
可能是最短的选择(尽管fgets
后跟strtok
,并且手动解析是可行的选择)。
您需要对字符串字段使用%[^;]
说明符(意思是:除了 ;
以外的字符串,{{1} }消耗实际的分号(我们明确要求不要使用它作为字符串字段的一部分)。最后一个字段应为;
,以消耗掉换行符,因为输入没有终止分号。
您还应该(始终)将通过%[^\n]
系列函数读取的每个字符串字段的长度限制为小于可用空间的长度(终止NUL字节为+1)。因此,例如,如果第一个字段最多为9个字符长,则需要scanf
,格式为char field1[10]
。
通常最好在格式字符串的开头放置一个空格以使用任何空格(例如前一个换行符)。
当然,您应该检查%9[^;]
的返回值,例如,如果根据示例,您有9个字段,则它应该返回fscanf
。
因此,最终结果将类似于:
9
(或者,用逗号分隔数字的字段也可以读为if (fscanf(file, " %9[^;];%99[^;];%99[^;];%d;%c;%99[^;];%d;%99[^;];%99[^\n]",
s.field1, s.field2, s.field3, &s.field4, …, s.field9) != 9) {
// error
break;
}
的四个独立字段,在这种情况下,计数最多为12。)
答案 1 :(得分:1)
这里有简单的令牌生成器。如我所见,您在这里有多个定界符(;
和,
)
str
-要标记的字符串
del
-包含定界符的字符串(仅在您使用";,"
或";"
的情况下)
allowempty
-如果为true,则如果存在两个或多个连续的定界符
返回值是指向令牌的NULL终止表。
char **mystrtok(const char *str, const char *del, int allowempty)
{
char **result = NULL;
const char *end = str;
size_t size = 0;
int extrachar;
while(*end)
{
if((extrachar = !!strchr(del, *end)) || !*(end + 1))
{
/* add temp variable and malloc / realloc checks */
/* free allocated memory on error */
if(!(!allowempty && !(end - str)))
{
extrachar = !extrachar * !*(end + 1);
result = realloc(result, (++size + 1) * sizeof(*result));
result[size] = NULL;
result[size -1] = malloc(end - str + 1 + extrachar);
strncpy(result[size -1], str, end - str + extrachar);
result[size -1][end - str + extrachar] = 0;
}
str = end + 1;
}
end++;
}
return result;
}
要释放令牌生成器分配的内存:
void myfree(char **ptr)
{
char **savedptr = ptr;
while(*ptr)
{
free(*ptr++);
}
free(savedptr);
}
功能很简单,但是您可以使用任何分隔符和任意数量的分隔符。