使用空格和分号解析CSV

时间:2018-04-20 19:30:06

标签: c csv

我需要解析以下CSV文件格式:

# cat data.csv
20000530 172700;0.930200;0.930200;0.930200;0.930200;0
20000530 173500;0.930400;0.930500;0.930400;0.930500;0
20000530 173800;0.930400;0.930400;0.930300;0.930300;0
20000530 174300;0.930100;0.930100;0.930000;0.930000;0

值按字符分隔;除了第一个用空格字符分隔的。

我已尝试使用以下代码来解析de CSV,但未正确解析时间(第二个CSV值)。

int read_data() {

    char _current_date[16];
    char _current_time[16];
    float _current_open;
    float _current_high;
    float _current_low;
    float _current_close;

    FILE *fp;

    fp = fopen("data.csv", "r");
    while(fscanf(fp, "%s %[ˆ;]%f;%f;%f;%f;", 
        _current_date, _current_time, 
        &_current_open, &_current_high, &_current_low, &_current_close) != EOF) {

      printf("%s\n", _current_date);
      printf("%s\n", _current_time);
    }
    fclose(fp);

}

输出是:

20000530

172700;0.930200;0.930200;0.930200;0.930200;0
0.930200;0.930200;0.930200;0
20000530
0.930200;0.930200;0.930200;0
173500;0.930400;0.930500;0.930400;0.930500;0
0.930500;0.930400;0.930500;0
20000530
0.930500;0.930400;0.930500;0
173800;0.930400;0.930400;0.930300;0.930300;0
0.930400;0.930300;0.930300;0
20000530

1 个答案:

答案 0 :(得分:2)

  

但未正确解析时间(第二个CSV值)。

OP的格式不消耗;,也不消耗最终0,并且没有正确检查返回值。使用== 6,而不是!= EOF

//                        ; not consumed
//                                    0 not consumed
while(fscanf(fp, "%s %[ˆ;]%f;%f;%f;%f;", 
    _current_date, _current_time,                             //    == 6
    &_current_open, &_current_high, &_current_low, &_current_close) != EOF) 
  

使用空格和分号解析CSV

要解析OP特定格式,以下建议各种想法。它不是CSV解析器(逗号分隔值),因为OP不使用逗号。

  1. 测试fopen()成功

    if (fp == NULL) {
      // maybe add message
      exit(EXIT_FAILURE);
    }
    
  2. 使用fgets()阅读 @Steve Summit

    char buf[100];   // suggest 2x expected need
    while (fgets(buf, sizeof buf, fp)) {
    
  3. 使用sscanf()并记录使用"%n"扫描的线条数量。将文本读入字符串时使用宽度限制。 @user3121023。我在格式中添加了一些空格以允许;之前的空格。也许使用%15[ˆ; ]来避免_current_time

    中的任何空格
      int n = 0;
      sscanf(buf, "%15s %15[ˆ;] ;%f ;%f ;%f ;%f ;0 %n", 
        _current_date, _current_time, 
        &_current_open, &_current_high, &_current_low, &_current_close,
        &n);
    
  4. 测试n现在是否指向buf

    的结尾
      if (n == 0 || buf[n] != '\0') {
        // Handle failure in some manner
        break;
      }
      // else Success!
    
  5. 使用数据。将<>之类的标记添加到字符串输出中,以帮助检测意外的前导/尾随空格。

      printf("<%s>\n", _current_date);
      printf("<%s>\n", _current_time);
    }
    
  6. 清理

    fclose(fp);