gpt4 book ai didi

c++ - 使用 C++ iostreams 解析具有空值的 CSV

转载 作者:太空宇宙 更新时间:2023-11-04 13:23:50 25 4
gpt4 key购买 nike

我无法正确解析 CSV 文件。数据行中的某些值可以为空,并且 my code当我在任何值行中有空白条目时无法正常工作。如果没有空白条目,程序将返回以下结果:

Symbol: GOOG
Name: Googl Inc.
Price: $570.25
High Today: $570.25
Low Today: $560.35

Symbol: APPL
Name: Apple Inc.
Price: $123.25
High Today: $124.25
Low Today: $125.35

如果我使用以下 CSV 字符串运行相同的程序,程序将停止并出现断言错误。这是由于解析器跳过了 adjacent ,, delimiters,因此数据行中的列数与标题中的列数不匹配。

std::stringstream ifs(
"Symbol,Name,Price,High Today,Low Today\n"
"GOOG,Googl Inc.,$570.25 ,$570.25 ,$560.35\n"
"APPL,Apple Inc.,$123.25 ,,$125.35\n");

这是我的代码:

#include <iostream>
#include <vector>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <cassert>
#include <locale>

// This ctype facet classifies commas and endlines as whitespace
struct csv_whitespace : std::ctype<char> {
static const mask* make_table() {
// make a copy of the "C" locale table
static std::vector<mask> v(classic_table(), classic_table() + table_size);
v[','] |= space; // comma will be classified as whitespace
v[' '] &= ~space; // space will not be classified as whitespace
return &v[0];
}
csv_whitespace(std::size_t refs = 0)
: ctype(make_table(), false, refs)
{}
};

static int row_end = std::ios_base::xalloc();

std::istream& record(std::istream& is) {
while (std::isspace(is.peek(), is.getloc())) {
int c(is.peek());
is.ignore();
if (c == '\n') {
is.iword(row_end) = 1;
is.setstate(std::ios_base::failbit);
}
}
return is;
}

template<class Iter1, class Iter2, class Function>
void for_each_binary_range(Iter1 first1, Iter1 last1,
Iter2 first2, Iter2 last2, Function f)
{
assert(std::distance(first1, last1) <=
std::distance(first2, last2));
while (first1 != last1) {
f(*first1++, *first2++);
}
}

int main(int argc, char *argv[])
{
std::stringstream ifs(
"Symbol,Name,Price,High Today,Low Today\n"
"GOOG,Googl Inc.,$570.25 ,$570.25 ,$560.35\n"
"APPL,Apple Inc.,$123.25 ,$124.25 ,$125.35\n");
//std::ifstream ifs("c:\\temp\\csvfile.csv", std::ios::in);
std::vector<std::string> keys, values;
ifs.imbue(std::locale(ifs.getloc(), new csv_whitespace));
bool bHeaderProcessed = false;
for (std::string item;;) {
if (ifs >> record >> item) {
if (!bHeaderProcessed) {
keys.push_back(item);
} else {
values.push_back(item);
}
} else if (ifs.eof()) {
// catch case where last line does not have trailing \n
if (!values.empty()) {
for_each_binary_range(std::begin(keys), std::end(keys),
std::begin(values), std::end(values),
[&](std::string const& key, std::string const& value) {
std::cout << key << ": " << value << std::endl;
std::cout << std::endl;
});
values.clear();
}
break;
} else if (ifs.iword(row_end)) {
// reset eol flag & clear stream state
ifs.iword(row_end) = 0;
// clear the fail-bit so we can stream more values
ifs.clear();
bHeaderProcessed = true;
if (!values.empty()) {
for_each_binary_range(std::begin(keys), std::end(keys),
std::begin(values), std::end(values),
[&](std::string const& key, std::string const& value) {
std::cout << key << ": " << value << std::endl;
});
values.clear();
std::cout << std::endl;
}
} else {
break;
}
}
return -1;
}

我基于我的原始代码记录得很好 here .不幸的是,问题的答案(通过现场演示 here )似乎无法处理有多行的情况,我无法让它处理标记为空的情况。

我的版本将每一行打印为一系列名称/值,它还处理有多行或一行不以新行结尾的情况。

逻辑在上面的链接答案中描述得很好

有人可以指出如何处理我在 csv 的数据行中有相邻分隔符的情况。

最佳答案

您的问题在于您期望如何解析数据与实际解析数据的方式。双“,,”被完全忽略,没有被推到值 vector 上。这意味着您的 values 数组的大小将短一个或多个。断言失败,因为断言键的大小 <= 值的大小。如果这发生在键 vector 中有双“,,”的地方,你就没问题。

std::stringstream ifs(
"Symbol,Name,,High Today,Low Today\n"
"GOOG,Googl Inc.,$570.25 ,$570.25 ,$560.35\n"
"APPL,Apple Inc.,$123.25 ,$124.25 ,$125.35\n");

尝试使用上面的方法并观察输出。

一个简单但不优雅的解决方案是在每个“,”之间插入一个空格,以便程序将其拾取。有很多更好的解决方案,但这应该能让你继续前进。

编辑:感谢您的理解。

关于c++ - 使用 C++ iostreams 解析具有空值的 CSV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34032154/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com