解析从Microsoft excel导出的csv文件

时间:2012-11-21 11:45:20

标签: c++ csv excel-2007

我有一个从Microsoft excel 2007导出的csv文件:

20;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
2;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
000055555;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
5;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
20;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
20;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
20;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
20;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
20;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
20;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
20;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
20;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8
20;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8

我使用this library来解析文件,但我遇到了一些问题:

  • 如果有空行,程序将崩溃。
  • 如果有空字段,程序也会崩溃。
;12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8 // will crash
20;12;25;25;;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8 // will crash

20;12;25;25; ;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8 // putting a space in empty field to help parser to not crash

一个简单的程序:

#include <iostream>
#include <fstream>
#include <string>
#include "csv_parser.h"
#include <cstdio>

#define FMT "%-20.20s%-12.12s%-25.25s%-25.25s%-8.8s%-3.3s%-1.1s%-10.10s%-3.3s%-1.1s%-10.10s%-3.3s%-1.1s%-10.10s%-3.3s%-1.1s%-10.10s%-12.12s%-8.8s%-8.8s\n"

using namespace std;


int main(int argc, char **argv)
{
    std::string sCol1, sCol2, sCol3, sCol4, sCol5, sCol6, sCol7, sCol8, sCol9, sCol10, sCol11, sCol12, sCol13, sCol14, sCol15, sCol16, sCol17, sCol18, sCol19, sCol20;


    const char * filename = "Book2.csv";
    const char field_terminator = ';';
    const char line_terminator  = '\n';
    const char enclosure_char   = '"';

    csv_parser file_parser;


    /* Specify the file to parse */
    file_parser.init(filename);

    /* Here we tell the parser how to parse the file */
    file_parser.set_enclosed_char(enclosure_char, ENCLOSURE_OPTIONAL);
    file_parser.set_field_term_char(field_terminator);
    file_parser.set_line_term_char(line_terminator);
    unsigned int row_count = 1U;


    FILE *hFile = fopen("Book2.txt", "w"); 

    /* Check to see if there are more records, then grab each row one at a time */
    while(file_parser.has_more_rows())
    {
        unsigned int i = 0;

        /* Get the record */
        csv_row row = file_parser.get_row();

        fprintf(hFile, FMT, row[0].c_str(), row[1].c_str(), row[2].c_str(), row[3].c_str(), row[4].c_str(), row[5].c_str(), row[6].c_str(), row[7].c_str(), row[8].c_str(), row[9].c_str(), row[10].c_str(), row[11].c_str(), row[12].c_str(), row[13].c_str(), row[14].c_str(), row[15].c_str(), row[16].c_str(), row[17].c_str(), row[18].c_str(), row[19].c_str());
        row_count++;
    }

    fclose(hFile);
    return 0;
}

在Unix / Linux中,解析器工作得很好,但在Windows中,库错误地解析行/字段。 是否有任何解析器支持可以使用分号解析csv文件作为字段分隔符。

1 个答案:

答案 0 :(得分:1)

可能的解决方案是使用boost::tokenizer。例如:

#include <string>
#include <iostream>
using std::cout;
using std::string;

#include <boost/tokenizer.hpp>
using boost::tokenizer;
using boost::escaped_list_separator;

typedef tokenizer<escaped_list_separator<char> > so_tokenizer;

int main()
{
    string a[] = { ";12;25;25;8;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8",
                   "20;12;25;25;;3;1;10;3;1;10;3;1;10;3;1;10;12;8;8" };

    for (int i = 0; i < 2; i++)
    {
        std::cout << a[i] << "\n";
        so_tokenizer tok(a[i], escaped_list_separator<char>('\\', ';', '\"'));
        for(so_tokenizer::iterator beg=tok.begin(); beg!=tok.end(); ++beg)
        {
            cout << "  tok=[" << *beg << "]\n";
        }
    }

    return 0;
}

有关在线演示,请参阅http://ideone.com/aWwAXK

使用std::ifstreamstd::getline()从文件中读取行并传递以进行标记化。