如何使用C++跳过csv中的标题行
How to skip header row in csv using C++
在我的场景中,我需要使用CSV创建一个参数文件。每一行都意味着一个配置数据,该行的第一个字段被视为标头,用作标识符。下面这样的CSV格式对我来说很容易解析:
1,field1,field2,field3,field4 // 1 indicated the TARGET that the other fields will be writted to.
1,field1,field2,field3,field4
2,field1,field2,field3,field4
2,field1,field2,field3,field4........
但它对用户并不友好。因此,我定义了一个csv文件,如下所示:
HeaderLine_Begin,1
field1,field2,field3,field4
field1,field2,field3,field4
HeaderLine_Begin,2
field1,field2,field3,field4
field1,field2,field3,field4
意味着,每一行都是数据,数据将由HeaderLine_Begin写入目标。我只是将ID与实际数据分开。然后,我创建了一个这样的结构:
enum myenum
{
ON,OFF,NOCHANGE
};
struct Setting
{
int TargetID;
string field1;
string field2;
myenum field3;
myenum field4;
};
我知道如何写一些代码来逐行读取csv,就像下面的一样
filename +=".csv";
std::ifstream file(filename.c_str());
std::string line;
while ( file.good() )
{
getline ( file, line, 'n' ); // read a line until last
if(line.compare(0,1,"#") == 0) // ignore the comment line
continue;
ParseLine();// DONE.Parse the line if it's header row OR data row
}
file.close(); // close file
我想做的是创建一个类似否决器设置的列表来保存数据。流程应该是,找到第一个headerID1,然后找到下一行。如果下一条线路是数据线路,则将其视为数据线路属于headerID1。如果下一个线路是另一个headerID,则再次循环。
问题是,在我找到headerRow之后,没有这样的std::getnextline(int-lineIndex)可以让我获取行。
您的输入循环应该更像:
int id = -1;
while (getline(file, line))
{
if (line.empty() || line[0] == '#')
continue;
if (starts_with_and_remove(line, "HeaderLine_Begin,"))
id = boost::lexical_cast<int>(line); // or id = atoi(line.c_str())
else
{
assert(id != -1);
...parse CSV, knowing "id" is in effect...
}
}
带有:
bool stats_with_and_remove(std::string& lhs, const std::string& rhs)
{
if (lhs.compare(0, rhs.size(), lhs) == 0) // rhs.size() > lhs.size() IS safe
{
lhs.erase(0, rhs.size());
return true;
}
return false;
}
最简单的解决方案是使用正则表达式:
std::string line;
int currentId = 0;
while ( std::getline( source, line ) ) {
trimCommentsAndWhiteSpace( line );
static std::regex const header( "HeaderLine_Begin,(\d+)" );
std::smatch match;
if ( line.empty() ) {
// ignore
} else if ( std::regex_match( line, match, header ) ) {
std::istringstream s( match[ 1 ] );
s >> currentId;
} else {
// ...
}
}
我经常使用这种策略来解析.ini
文件同样的问题:节头与其他事情。
trimCommentsAndWhiteSpace
可以简单到:
void
trimCommentsAndWhiteSpace( std::string& line )
{
if ( !line.empty() && line[0] == '#' ) {
line = "";
}
}
很容易将其扩展为处理行末注释然而,这通常是一项好政策(在类似this)来修剪前导和尾随空格---尾随尤其是,因为人类读者在看文件。
当然,也可以使用正则表达式要树化为注释的行("\s*#.*");这很管用符合您当前的定义,但没有真正扩展适用于行尾注释,尤其是如果您希望允许字段中带引号的字符串中的#
。
最后一条评论是:你的循环不正确。你不测试getline
在使用其结果之前成功,并且即使没有其他内容,file.good()
也可能返回true阅读(file.good()
就是其中之一历史原因;在任何情况下,使用)
- 正在将csv文件读取为双精度矢量
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 对于C++,方括号中的标题必须总是在引号中的标题之上吗
- 如何选择在 csv 文件中输出的位置
- 库标题在标题中不可见,但在 cmake build 下.cpp文件中完全可见.为什么?
- 为什么我不应该把所有东西都放在标题中?
- 有没有办法在不使用 getline() 的情况下从.csv文件中读取?
- WinAPI 检查窗口是否具有常规标题栏
- 如何更改窗体上所有控件的标题?[C++生成器]
- 提升用于解析标题列的精神语法
- 如何从 CSV 获取数据并将其存储在 C++ 中的表对象中
- 无法读取C++中的 CSV 文件
- 所以我正在为我的学校作业练习继承,但我无法正确实施标题保护
- 流:CSV 文件中的换行符
- 如何删除已输入的书以及如何使标题,语言和名称在上面放置空格不会出错?
- 是否可以使用 Python csv 阅读器读取使用 C++ std::setw 生成的文件?
- 使用从文件(stod、strtod、atof)中提取的数据C++从字符串转换为双精度.csv
- 将一维数组写入 CSV C++中的不同列?
- 如何使用C++跳过csv中的标题行
- 使用Rfc4180CsvParser将CSV导入Vertica并排除标题行