【问题标题】:trouble using strtok to parse CSV file with date/time in c++在 C++ 中使用 strtok 解析带有日期/时间的 CSV 文件时遇到问题
【发布时间】:2015-09-22 21:59:23
【问题描述】:

我有一个包含日期的 CSV 文件(我从 excel 转换而来),但我无法使用 strtok 函数解析它们。当我从 CSV 文件中删除带有日期的列时,它可以正常工作,但否则会出现错误。我已经玩了几个小时,但错误不会消失。我非常感谢任何帮助/建议!我是一个编程初学者。这是我所拥有的(粗体部分是我为程序工作而取出的部分,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

【问题讨论】:

标签: c++ date parsing csv strtok


【解决方案1】:

看这一行:

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 之前,您需要从行中复制数据,这对您有好处。

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

根据我的上述建议,这里有几件事已经过时了:

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

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

在 while 循环中,如果 strtok 由于行格式不正确而返回 NULL,则无法防止破坏。

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

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

mymap[n] = temp;

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-08
      相关资源
      最近更新 更多