在 C++ 中使用 strtok 解析带有 date/time 的 CSV 文件时遇到问题

trouble using strtok to parse CSV file with date/time in c++

我有一个包含日期的 CSV 文件(我从 excel 转换而来),但我在使用 strtok 函数解析它们时遇到了问题。当我从 CSV 文件中删除带有日期的列时,它工作正常,但否则我会收到错误消息。我已经玩了几个小时,但错误不会消失。我将不胜感激 help/advice!我是一个编程初学者。这是我所拥有的(粗体部分是我为程序工作而取出的部分,CSV 文件中没有日期):

void parseFile (ifstream &myfile) {

string line;
int n = 1;

while ( myfile.good() ) {

    //storing each line into char array
    getline(myfile,line);
    char data[100];
    for (int g = 0; g <= line.size(); g++) {
        data[g] = line[g];
    }

    //using strtok to read char array
    char * tok;
    tok = strtok (data,",");

    while (tok != NULL) {

        temp.patientID = atol(tok);
        tok = strtok(NULL, ",");

        temp.result = atof(tok);
        tok = strtok(NULL, ",");
        tok = strtok(NULL, "/");
        tok = strtok(NULL, "/");

        temp.date = atof(tok);
        tok = strtok(NULL, " ");
        tok = strtok(NULL, ":");
        tok = strtok(NULL, ":");

        temp.time = atof(tok);
        tok = strtok(NULL, ",");

        //getting each component and storing into map that stores parsed info, mymap
        mymap.insert (pair<int,testInfo>(n,temp));
        n++;
    }
}

}

我的 CSV 文件看起来像这样:

1000856,0,28/09/2014 02:34:37
1002259,0.008,15/09/2014 23:14:11
1002259,0.002,18/09/2014 10:44:18
1002259,0.005,18/09/2014 16:54:52
1003348,0.038,20/03/2015 12:50:46

您正在搜索一个逗号然后需要,这意味着您在 temp.result = atof(tok); tok = strtok(NULL, ","); 之后的令牌指向字符串的末尾。删除那条线,我认为它应该做你想做的。当您尝试将 NULL 输出从 strtok 转换为浮点数时,会发生段错误。

查看这一行:

1000856,0,28/09/2014 02:34:37

我看到以下分隔符:,,// ::

你为 ,,,// ::,

努力

前面的 ', 太多了。

该行将解析为:“1000856”“0”“28/09/2014 02:34:37”NULL NULL NULL NULL NULL NULL,这些 NULL 将对 atofs 造成严重破坏。

此外,temp.date = atof(tok);不会给你约会。它会给你部分日期。我认为的月份。 temp.time = atof(tok); 只是给你秒。

对于此任务,strtok 的更好选择是 stringstream 和 getline(stream &, string &, char)。这家伙让你设置分隔符等东西是这样的:

std::stringstream linestream(line)
std::string tok;
if (getline(linestream, tok, ','))
{ // got a token
    try
    { 
        temp.patientID = std::stol(tok);
    }
    catch (...)
    {
        // handle bad input number
    }
}

我还将 atol 替换为 std::stol,因为有了它,您可以留在字符串区域并在数字未转换时捕获异常。 atol 无法转换时静默失败。

如果不允许使用流,请查看 sscanf。对于像您这样的定期格式化数据,与 strtok 相比,它是炸弹。

顺便说一句,你知道在将数据传递到 strtok 之前需要从 line 中复制数据,这对你很好。

上面的代码很容易写,但执行起来可能会很慢,但在这里应该没问题。

我上面的建议已经过时了,这里有一些要看的东西:

char data[100];
for (int g = 0; g <= line.size(); g++) {
    data[g] = line[g];
}

g <= line.size() 将始终在字符串末尾读取一个。很棒,因为它保留了 NULL,但不完全符合犹太洁食标准。我不确定 C++ 是否保证那里会有 NULL。这些天我可能应该购买并阅读标准的副本。除了测试 g <= line.size() 之外,您还应该测试 g < 100 以防止溢出 char 数组。

在 while 循环内,如果 strtok returns NULL 因为格式不正确的行,则没有任何东西可以防止破坏。

如果mymap是std::map,你可以简化

mymap.insert (pair<int,testInfo>(n,temp));

mymap[n] = temp;