引号中带有逗号的C++CSV解析
C++ CSV Parsing with Commas Inside of Quotes
我正在构建一个C++CSV数据解析器。我正在尝试访问文件的第一列和第十五列,并使用getline
命令将它们读取到两个数组中。例如:
for(int j=0;j<i;j++)
{
getline(posts2,postIDs[j],',');
for(int k=0;k<14;k++)
{
getline(posts2,tossout,',');
}
getline(posts2,answerIDs[j],',');
getline(posts2,tossout,'r');
但是,在第一列和第十五列之间是一个用引号括起来的列,其中包含各种逗号和松散引号。例如:
"abc,defghijk."Lmnopqrs,"tuv","wxyz.",…<
避免这个专栏的最佳方式是什么?我无法在上面划线,因为里面有引号和逗号。遇到引号后,我是否应该逐个阅读被引用的垃圾字符,直到我按顺序找到",?
此外,我还看到了其他解决方案,但所有这些解决方案都是Windows/Vistudio独有的。我运行的是Mac OSX 10.8.3版本,Xcode为3.2.3。
提前感谢!Drew
CSV格式没有正式的标准,但让我们首先注意你引用的丑陋专栏:
"abc, defghijk. "Lmnopqrs, "tuv,"" wxyz.",
不符合CSV的基本规则,因为其中两个是:-
1) 带有嵌入逗号的字段必须加引号。
2) 每个嵌入的双引号字符必须由一对双引号字符表示。
如果问题列遵守规则1),那么它就不遵守规则2)。但我们可以理解以便遵守规则1)-因此我们可以说它的结束位置-如果我们平衡双引号,例如
[abc, defghijk. [Lmnopqrs, ]tuv,[] wxyz.],
最外面的平衡引号将列括起来。平衡的内部报价除了平衡之外,可能没有任何其他内部迹象使它们内部化。
我们想要一个规则,将此文本解析为一列,与规则1一致),并且还将解析也要遵守规则2)。刚刚展示的平衡表明可以做到,因为遵守这两个规则的列必然是平衡能力也很强。
建议的规则是:
- 列运行到前面有0个双引号的第一个逗号或前面是偶数个双引号中的最后一个
如果逗号前有偶数个双引号,那么我们就知道我们可以至少用一种方法来平衡附引号和其他引号。
您正在考虑的更简单的规则:
在遇到引用后,我应该逐个阅读引用的垃圾字符,直到我找到",按顺序?
如果遇到不遵守规则2)的某些列,将失败,例如
"超级"豪华"卡车"
更简单的规则将在""luxurious""
之后终止列。但自从该列符合规则2),相邻的双引号为"转义"双引号-引号,没有定界意义。另一方面,建议规则仍然正确地解析列,在truck"
之后终止它。
下面是一个演示程序,其中函数get_csv_column
解析列按照建议的规则:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
/*
Assume `in` is positioned at start of column.
Accumulates chars from `in` as long as `in` is good
until either:-
- Have consumed a comma preceded by 0 quotes,or
- Have consumed a comma immediately preceded by
the last of an even number of quotes.
*/
std::string get_csv_column(ifstream & in)
{
std::string col;
unsigned quotes = 0;
char prev = 0;
bool finis = false;
for (int ch; !finis && (ch = in.get()) != EOF; ) {
switch(ch) {
case '"':
++quotes;
break;
case ',':
if (quotes == 0 || (prev == '"' && (quotes & 1) == 0)) {
finis = true;
}
break;
default:;
}
col += prev = ch;
}
return col;
}
int main()
{
ifstream in("csv.txt");
if (!in) {
cout << "Open error :(" << endl;
exit(EXIT_FAILURE);
}
for (std::string col; in; ) {
col = get_csv_column(in),
cout << "<[" << col << "]>" << std::endl;
}
if (!in && !in.eof()) {
cout << "Read error :(" << endl;
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
它包含<[...]>
中的每一列,不包括换行符,并且包括终端",",每列:
文件csv.txt
为:
...,"abc, defghijk. "Lmnopqrs, "tuv,"" wxyz.",...,
",","",
Year,Make,Model,Description,Price,
1997,Ford,E350,"Super, ""luxurious"", truck",
1997,Ford,E350,"Super, ""luxurious"" truck",
1997,Ford,E350,"ac, abs, moon",3000.00,
1999,Chevy,"Venture ""Extended Edition""","",4900.00,
1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00,
1996,Jeep,Grand Cherokee,"MUST SELL!
air, moon roof, loaded",4799.00,
输出为:
<[...,]>
<["abc, defghijk. "Lmnopqrs, "tuv,"" wxyz.",]>
<[...,]>
<[
",",]>
<["",]>
<[
Year,]>
<[Make,]>
<[Model,]>
<[Description,]>
<[Price,]>
<[
1997,]>
<[Ford,]>
<[E350,]>
<["Super, ""luxurious"", truck",]>
<[
1997,]>
<[Ford,]>
<[E350,]>
<["Super, ""luxurious"" truck",]>
<[
1997,]>
<[Ford,]>
<[E350,]>
<["ac, abs, moon",]>
<[3000.00,]>
<[
1999,]>
<[Chevy,]>
<["Venture ""Extended Edition""",]>
<["",]>
<[4900.00,]>
<[
1999,]>
<[Chevy,]>
<["Venture ""Extended Edition, Very Large""",]>
<[,]>
<[5000.00,]>
<[
1996,]>
<[Jeep,]>
<[Grand Cherokee,]>
<["MUST SELL!
air, moon roof, loaded",]>
<[4799.00]>
这是c++中最优雅的读取.csv文件的方法,该文件中带有引号(即引号)的标记内有逗号:
std::string header;
std::vector<std::vector<std::string>> cSVRows;
std::ifstream reader(fileName);
if (reader.is_open()) {
std::string line, column, id;
std::getline(reader, line);
header = line;
while (std::getline(reader, line)) {
std::stringstream ss(line);
std::vector<std::string> columns;
bool withQ = false;
std::string part{""};
while (std::getline(ss, column, ',')) {
auto pos = column.find(""");
if (pos < column.length()) {
withQ = !withQ;
part += column.substr(0, pos);
column = column.substr(pos + 1, column.length());
}
if (!withQ) {
column += part;
columns.emplace_back(std::move(column));
part = "";
} else {
part += column + ",";
}
}
cSVRows.emplace_back(columns);
}
}
- 使用 istream 提取运算符进行 csv 解析:如何检测缺失的字段值?
- 获取线函数不会解析 CSV 文件中的行尾
- 解析具有提升精神的简单 csv 表
- Boost Tokenizer无法解析具有带有双引号的字段的CSV文件
- 如何使用 Boost 内存映射解析 C++ 中的 CSV?
- 在 C++ 中解析 csv 退出代码 11
- 在开关盒循环中使用未删除的标识符来解析 CSV 文件
- 如何使用没有清晰格式样式的C 解析CSV文件
- 解析 csv 文件,"malloc: *** error for object 0x7ffeeb4f4b80: pointer being freed was not allocated"出现此错误
- 解析一般CSV读取功能时,如何处理不同的数据类型?(不明确指定它们)
- 解析从 Excel 导出Microsoft csv 文件
- 具有多个 EOL 字符的常规 CSV 解析器
- 我应该如何在C++中读取和解析(真实的、正确的、功能齐全的)CSV
- 提升精神解析 CSV,列顺序可变
- 按行解析和排序 csv 文件
- 解析 csv 文件 c++
- C++中的快速CSV解析器
- 引号中带有逗号的C++CSV解析
- CSV解析器的性能瓶颈
- C++ - 无法将 CSV 解析为我的结构