c++ - 如何解析带引号字段中嵌入逗号的 CSV?

标签 c++ csv parsing

我已经尝试了其他答案中提到的一些修复,但它们对我的输出没有影响。我不打算使用 boost spirit,因为我不确定它是否是满足我需求的最佳选择。此外,类似的帖子不涉及包含逗号的引用 Material ,这是我目前要解决的最后一个问题。

这是一个 C++ 程序。我正在使用 CSV 文件作为输入。该文件给出了印章的特征,每个条目有 23 个值(列)。当我输出 rawdata[22] 时,我希望看到第一组数据的最后一个条目。相反,我看到了最后一个条目(请愿书),然后是下一个印章的第一个条目(2055)。当我在十六进制编辑器中打开它时,我看到这两个词由“.”分隔。十六进制字符为 0a。我尝试将\r、\n、\r\n 设置为分隔符,但它们不起作用。我不能使用“,”作为分隔符,因为它在字符串中使用,我测试了它是否对我的问题有效,但它没有。如何分离这些值?

输出:

请求 2055

示例输入:

SpeciesID,Kingdom,Phylum,Class,Order,Family,Genus,Species,Authority,Infraspecific rank,Infraspecific name,Infraspecific authority,Stock/subpopulation,Synonyms,Common names (Eng),Common names (Fre),Common names (Spa),Red List status,Red List criteria,Red List criteria version,Year assessed,Population trend,Petitioned
2055,ANIMALIA,CHORDATA,MAMMALIA,CARNIVORA,OTARIIDAE,Arctocephalus,australis,"(Zimmermann, 1783)",,,,,Arctophoca australis,South American Fur Seal,Otarie fourrure Australe,Oso Marino Austral,LC,,3.1,2016,increasing,N
41664,ANIMALIA,CHORDATA,MAMMALIA,CARNIVORA,OTARIIDAE,Arctocephalus,forsteri,"(Lesson, 1828)",,,,,Arctocephalus australis subspecies forsteri|Arctophoca australis subspecies forsteri,"New Zealand Fur Seal, Antipodean Fur Seal, Australasian Fur Seal, Black Fur Seal, Long-nosed Fur Seal, South Australian Fur Seal",,,LC,,3.1,2015,increasing,N

my code:

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

int main() {
    string line;
    vector<string> rawdata;
    ifstream file ( "/Users/darla/Desktop/Programs/seals.csv" );
    if ( file.good() )
   {
    while(getline(file, line, '"')) {
        stringstream ss(line);
        while (getline(ss, line, ',')) {
            rawdata.push_back(line);
        }
        if (getline(file, line, '"')) {
            rawdata.push_back(line);
        }
    }
   }
    cout << rawdata[22] << endl;


    return 0;

最佳答案

这远非一个完整的 CSV 解析器,可以提高效率,但它可以完成工作,正确解析您的文件并处理双引号。

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>

int main()
{
    std::string line;
    std::vector<std::vector<std::string>> lines;
    std::ifstream file("/Users/darla/Desktop/Programs/seals.csv");

    if (file)
    {
        while (std::getline(file, line))
        {
            size_t n = lines.size();
            lines.resize(n + 1);

            std::istringstream ss(line);
            std::string field, push_field("");
            bool no_quotes = true;

            while (std::getline(ss, field, ',')) 
            {
                if (static_cast<size_t>(std::count(field.begin(), field.end(), '"')) % 2 != 0)
                {
                    no_quotes = !no_quotes;
                }

                push_field += field + (no_quotes ? "" : ",");

                if (no_quotes)
                {
                    lines[n].push_back(push_field);
                    push_field.clear();
                }
            }
        }
    }

    for (auto line : lines)
    {
        for (auto field : line)
        {
            std::cout << "| " << field << " |";
        }

        std::cout << std::endl << std::endl;
    }

    return 0;
}

enter image description here

一个解释。该程序读取文件行并尝试按字段解析每一行,以逗号分隔,然后将结果存储在 vector 的 vector 中。如果遇到带双引号的字段,并且双引号是奇数,这意味着它是一个开放字段,因此会读入更多字段,直到找到关闭字段,然后存储完整的字段。如果字段包含偶数个双引号或没有,则立即存储。希望这会有所帮助。

关于c++ - 如何解析带引号字段中嵌入逗号的 CSV?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48085842/

相关文章:

c# - Visual Studio C#语法/句子结构检查方法

c# - 将 PictureBox 对象传递给类中的方法

c++ - 你好!我想让我的程序定期显示一段文本。作为 "loading bar"的东西。

c++ - 如何从驱动器号中获取驱动器名称?

java - 如何使用 OpenCSV 跳过 csv 文件中嵌入的 "newlines"

javascript - html输入表单写入csv

c++ - 理解指针

c++ - 如何加快 C++ 中的矩阵乘法?

csv - 导入大型 CSV 文件的最佳实践

php - 将 HTML 文件解析为 PHP