Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从CSV文件中读取并分离要存储在C结构中的字段_C_String_Struct_Fgets_Strtok - Fatal编程技术网

从CSV文件中读取并分离要存储在C结构中的字段

从CSV文件中读取并分离要存储在C结构中的字段,c,string,struct,fgets,strtok,C,String,Struct,Fgets,Strtok,我试图从CSV文件中读取数据,并将每个字段存储到结构中的一个变量中。我使用fgets和strtok来分隔每个字段。但是,我无法处理字段中包含逗号的特殊字段 typedef struct { char name[20+1]; char surname[20+1]; char uniqueId[10+1]; char address[150+1]; } employee_t; void readFile(FILE *fp, employee_t *employees

我试图从CSV文件中读取数据,并将每个字段存储到结构中的一个变量中。我使用fgets和strtok来分隔每个字段。但是,我无法处理字段中包含逗号的特殊字段

typedef struct {
    char name[20+1];
    char surname[20+1];
    char uniqueId[10+1];
    char address[150+1];
} employee_t;

void readFile(FILE *fp, employee_t *employees[]){
    int i=0;
    char buffer[205];
    char *tmp;
    
    while (fgets(buffer,205,fp) != NULL) {
        employee_t *new = (employee_t *)malloc(sizeof(*new));
        
        tmp = strtok(buffer,",");
        strcpy(new->name,tmp);
        
        tmp = strtok(buffer,",");
        strcpy(new->surname,tmp);
        
        tmp = strtok(buffer,",");
        strcpy(new->uniqueId,tmp);

        tmp = strtok(buffer,",");
        strcpy(new->address,tmp);

        employees[i++] = new;
        free(new);
    }
}
输入如下:

Jim,Hunter,9239234245,"8/1 Hill Street, New Hampshire"
Jay,Rooney,92364434245,"122 McKay Street, Old Town"
Ray,Bundy,923912345,NOT SPECIFIED
我试着用这个代码打印代币,结果是:

Jim 
Hunter 
9239234245
"8/1 Hill Street
 New Hampshire"

我不知道如何处理地址字段,因为其中一些字段可能包含逗号。我试着一个字符一个字符地读,但不知道如何使用单个循环在结构中插入字符串。有人能帮我解决这个问题吗?

strcspn
可以用来查找双引号或双引号加逗号。
原始字符串未修改,因此可以使用字符串文字。
双引号的位置并不重要。他们可以在任何领域

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

int main( void) {

    char *string[] = {
        "Jim,Hunter,9239234245,\"8/1 Hill Street, New Hampshire\""
        , "Jay,Rooney,92364434245,\"122 McKay Street, Old Town\""
        , "Ray,Bundy,923912345,NOT SPECIFIED"
        , "Ray,Bundy,\" double quote here\",NOT SPECIFIED"
    };

    for ( int each = 0; each < 4; ++each) {
        char *token = string[each];
        char *p = string[each];

        while ( *p) {
            if ( '\"' == *p) {//at a double quote
                p += strcspn ( p + 1, "\"");//advance to next double quote
                p += 2;//to include the opening and closing double quotes
            }
            else {
                p += strcspn ( p, ",\"");//advance to a comma or double quote
            }
            int span = ( int)( p - token);
            if ( span) {
                printf ( "token:%.*s\n", span, token);//print span characters

                //copy to another array
            }
            if ( *p) {//not at terminating zero
                ++p;//do not skip consecutive delimiters

                token = p;//start of next token
            }
        }
    }
    return 0;
}
#包括
#包括
#包括
内部主(空){
字符*字符串[]={
吉姆,亨特,9239234245,“新罕布什尔州希尔街8/1号”
“杰伊,鲁尼,92364434245,老城麦凯街122号”
,“Ray,Bundy,923912345,未指定”
,“Ray,Bundy,\“此处双引号\”,未指定
};
for(int-each=0;each<4;++each){
char*token=string[each];
char*p=字符串[每个];
而(*p){
如果('\'=*p){//在双引号处
p+=strcspn(p+1,“\”);//前进到下一个双引号
p+=2;//包含开始和结束双引号
}
否则{
p+=strcspn(p,,\);//前进到逗号或双引号
}
int span=(int)(p-标记);
如果(跨度){
printf(“标记:%.*s\n”,span,标记);//打印span个字符
//复制到另一个数组
}
如果(*p){//不在零位
++p、 //不要跳过连续分隔符
令牌=p;//开始下一个令牌
}
}
}
返回0;
}
编辑:复制到变量
计数器可用于在处理字段时跟踪字段

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

#define SIZENAME 21
#define SIZEID 11
#define SIZEADDR 151

typedef struct {
    char name[SIZENAME];
    char surname[SIZENAME];
    char uniqueId[SIZEID];
    char address[SIZEADDR];
} employee_t;

int main( void) {

    char *string[] = {
        "Jim,Hunter,9239234245,\"8/1 Hill Street, New Hampshire\""
        , "Jay,Rooney,92364434245,\"122 McKay Street, Old Town\""
        , "Ray,Bundy,923912345,NOT SPECIFIED"
        , "Ray,Bundy,\"quote\",NOT SPECIFIED"
    };
    employee_t *employees = malloc ( sizeof *employees * 4);
    if ( ! employees) {
        fprintf ( stderr, "problem malloc\n");
        return 1;
    }

    for ( int each = 0; each < 4; ++each) {
        char *token = string[each];
        char *p = string[each];
        int field = 0;

        while ( *p) {
            if ( '\"' == *p) {
                p += strcspn ( p + 1, "\"");//advance to a delimiter
                p += 2;//to include the opening and closing double quotes
            }
            else {
                p += strcspn ( p, ",\"");//advance to a delimiter
            }
            int span = ( int)( p - token);
            if ( span) {
                ++field;
                if ( 1 == field) {
                    if ( span < SIZENAME) {
                        strncpy ( employees[each].name, token, span);
                        employees[each].name[span] = 0;
                        printf ( "copied:%s\n", employees[each].name);//print span characters
                    }
                }
                if ( 2 == field) {
                    if ( span < SIZENAME) {
                        strncpy ( employees[each].surname, token, span);
                        employees[each].surname[span] = 0;
                        printf ( "copied:%s\n", employees[each].surname);//print span characters
                    }
                }
                if ( 3 == field) {
                    if ( span < SIZEID) {
                        strncpy ( employees[each].uniqueId, token, span);
                        employees[each].uniqueId[span] = 0;
                        printf ( "copied:%s\n", employees[each].uniqueId);//print span characters
                    }
                }
                if ( 4 == field) {
                    if ( span < SIZEADDR) {
                        strncpy ( employees[each].address, token, span);
                        employees[each].address[span] = 0;
                        printf ( "copied:%s\n", employees[each].address);//print span characters
                    }
                }
            }
            if ( *p) {//not at terminating zero
                ++p;//do not skip consceutive delimiters

                token = p;//start of next token
            }
        }
    }
    free ( employees);
    return 0;
}
#包括
#包括
#包括
#定义SIZENAME 21
#定义SIZEID 11
#定义大小ADR 151
类型定义结构{
字符名[SIZENAME];
查氏[SIZENAME];
字符唯一性[SIZEID];
字符地址[SIZEADDR];
}雇员;;
内部主(空){
字符*字符串[]={
吉姆,亨特,9239234245,“新罕布什尔州希尔街8/1号”
“杰伊,鲁尼,92364434245,老城麦凯街122号”
,“Ray,Bundy,923912345,未指定”
,“Ray,Bundy,\“quote\”,未指定
};
employee_t*employees=malloc(sizeof*employees*4);
如果(!员工){
fprintf(stderr,“问题malloc\n”);
返回1;
}
for(int-each=0;each<4;++each){
char*token=string[each];
char*p=字符串[每个];
int字段=0;
而(*p){
如果(“\”==*p){
p+=strcspn(p+1,“\”);//前进到分隔符
p+=2;//包含开始和结束双引号
}
否则{
p+=strcspn(p,,\);//前进到分隔符
}
int span=(int)(p-标记);
如果(跨度){
++场;
if(1==字段){
if(跨度
在我看来,这类问题需要一个“适当的”标记器,可能基于有限状态机(FSM)。在本例中,您将逐个字符扫描输入字符串,将每个字符分配给一个类。标记器将在特定状态下启动,并且根据读取的字符的类别,它可能保持在相同的状态,或者移动到新状态。也就是说,状态转换由当前状态和所考虑的角色的组合控制

例如,如果在起始状态下读取双引号,则会转换为“在引号字符串中”状态。在这种状态下,逗号不会导致转换到新状态——它只会被添加到正在构建的令牌中。在任何其他状态下,逗号都具有特殊意义,因为它表示标记的结尾。你必须弄清楚什么时候你需要在代币之间加入额外的空格,无论