【发布时间】:2022-01-14 22:51:21
【问题描述】:
我将以下格式的配置文件读入我的 C++ 代码:
# name score
Marc 19.7
Alex 3.0
Julia 21.2
到目前为止,我已经调整了一个在这里找到的解决方案:Parse (split) a string in C++ using string delimiter (standard C++)。比如下面的代码sn -p 逐行读入文件,对每一行调用parseDictionaryLine,它会丢弃第一行,按照原线程中描述的方式拆分字符串,并将值插入到一个(self -实现)哈希表。
void parseDictionaryLine(std::string &line, std::string &delimiter, hash_table &table) {
size_t position = 0;
std::string name;
float score;
while((position = line.find(delimiter)) != std::string::npos) {
name = line.substr(0, position);
line.erase(0, position + delimiter.length());
score = stof(line);
table.hinsert(name, score);
}
}
void loadDictionary(const std::string &path, hash_table &table) {
std::string line;
std::ifstream fin(path);
std::string delimiter = " ";
int lineNumber = 0;
if(fin.is_open()) {
while(getline(fin, line)) {
if(lineNumber++ < 1) {
continue; // first line
}
parseDictionaryLine(line, delimiter, table);
}
fin.close();
}
else {
std::cerr << "Unable to open file." << std::endl;
}
}
我的问题是,C++ 中是否有更优雅的方式来完成这项任务?特别是,是否有 (1) 更好的 split 函数,例如在 Python 中,(2) 更好的方法来测试一行是否是注释行(以 # 开头),例如 startsWith (3) 甚至可能在迭代器中处理类似于 Python 中的上下文管理器的文件并确保文件实际上将被关闭?我的解决方案适用于此处显示的简单案例,但随着更复杂的变化(例如位于不可预测位置的多个注释行和更多参数)变得更加笨拙。此外,让我担心的是,我的解决方案没有检查文件是否真的符合规定的格式(每行两个值,第一个是字符串,第二个是浮点数)。用我的方法实现这些检查似乎很麻烦。
我知道有 JSON 和其他文件格式以及为此用例制作的库,但我正在处理遗留代码,不能去那里。
【问题讨论】:
-
boost.org/doc/libs/1_78_0/doc/html/string_algo/… 你不必担心调用
fin.close()它会在你的函数结束时自动完成 -
如果你知道一个字符串的具体格式
std::istringstream和普通的流提取操作符>>?否则std::istringstream(再次)和std::getline在循环中使用分隔符作为“换行符”?而且网上肯定有不少“用分隔符分割”的例子。 -
@AlanBirtles 我会检查一下 boost 解决方案,这似乎很有帮助。怎么会自动调用
fin.close()?如果程序之前崩溃,例如在尝试将字符串转换为浮点数时,我猜该文件将永远不会关闭。 @Some 程序员老兄istringstream的好点,这是第二种选择,是的,有例子(我发布的一个)。整个字符串处理对我来说似乎有点笨拙。 -
fin是一个本地对象,因此在函数结束时会自动销毁(除非您的程序完全退出并出现一些非 C++ 异常,如 seg-fault,在这种情况下操作系统将关闭任何打开的文件句柄),析构函数调用close。 -
听起来很简单,试试SO search。在那里,您至少会找到一些建议,甚至是解决方案。