C ++ CSV行,逗号和双引号内的字符串

时间:2016-02-25 21:51:03

标签: c++ csv double quotes comma

我正在用C ++读取CSV文件,行格式是这样的:

“小学,中学,第三”,“小学”,“中学”,18,4,0,0,0

(注意空值)

当我这样做时:

while (std::getline(ss, csvElement, ',')) {
   csvColumn.push_back(csvElement);
}

这会将第一个字符串拆分成不正确的部分。

迭代时如何保留字符串?我尝试做上面的组合,同时也抓住由双引号分隔的行,但我得到了狂野的结果。

3 个答案:

答案 0 :(得分:2)

使用std::quoted可以从输入流中读取引用的字符串。

#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>

int main() {
    std::stringstream ss;
    ss << "\"Primary, Secondary, Third\", \"Primary\", , \"Secondary\", 18, 4, 0, 0, 0";

    while (ss >> std::ws) {
        std::string csvElement;

        if (ss.peek() == '"') {
            ss >> std::quoted(csvElement);
            std::string discard;
            std::getline(ss, discard, ',');
        }
        else {
            std::getline(ss, csvElement, ',');
        }

        std::cout << csvElement << "\n";
    }
}

Live Example

需要注意的是,只有当值的第一个非空白字符是双引号时,才会提取引用的字符串。此外,引用字符串之后的任何字符都将被丢弃,直到下一个逗号。

答案 1 :(得分:1)

您需要解释逗号,具体取决于您是否在引用之前。这对于getline()而言过于复杂。

解决方案是使用getline()读取整行,并通过逐字符遍历字符串来解析该行,并维护指示符是否在双引号之间。

这是第一个“原始”示例(字段中不删除双引号,并且不解释转义字符):

string line; 
while (std::getline(cin, line)) {        // read full line
    const char *mystart=line.c_str();    // prepare to parse the line - start is position of begin of field
    bool instring{false};                
    for (const char* p=mystart; *p; p++) {  // iterate through the string
        if (*p=='"')                        // toggle flag if we're btw double quote
            instring = !instring;     
        else if (*p==',' && !instring) {    // if comma OUTSIDE double quote
            csvColumn.push_back(string(mystart,p-mystart));  // keep the field
            mystart=p+1;                    // and start parsing next one
        }
    }
csvColumn.push_back(string(mystart));   // last field delimited by end of line instead of comma
}

Online demo

答案 2 :(得分:0)

  

迭代时如何保留字符串?

这是我使用过的C ++方法。

我注意到你只有3种字段类型:string,null和int。

以下方法使用这些字段类型(在方法&#34; void init()&#34;)中,按顺序每行显示字段,有时使用string :: find()(而不是getline)( ))定位现场结束。

3种方法中的每一种都使用擦除字符串中的字符。我知道擦除很慢,但为了方便我做了这个选择。 (擦除更容易测试,只需在每次提取后添加一个cout)。可以通过搜索开始索引的适当处理(如果需要)来移除/替换擦除。

getTitle