C++ 在C+;中实现逐行文件解析器时遇到问题+;
我很难在C++11中实现一个简单的文件解析器,它逐行读取一个文件并对该行进行标记。它应该妥善管理其资源。解析器的用法应类似于:C++ 在C+;中实现逐行文件解析器时遇到问题+;,c++,parsing,file-io,c++11,C++,Parsing,File Io,C++11,我很难在C++11中实现一个简单的文件解析器,它逐行读取一个文件并对该行进行标记。它应该妥善管理其资源。解析器的用法应类似于: Parser parser; parser.open("/path/to/file"); std::pair<int> header = parser.getHeader(); while (parser.hasNext()) { std::vector<int> tokens = parser.getNext(); } parser.c
Parser parser;
parser.open("/path/to/file");
std::pair<int> header = parser.getHeader();
while (parser.hasNext()) {
std::vector<int> tokens = parser.getNext();
}
parser.close();
解析器;
open(“/path/to/file”);
std::pair header=parser.getHeader();
while(parser.hasNext()){
std::vector tokens=parser.getNext();
}
parser.close();
因此,解析器
类需要一个成员std::ifstream文件
(或者std::ifstream*文件
)
1) 构造函数应该如何初始化此->文件
2) 如何打开
方法将此->文件
设置为输入文件
3) 如何将文件中的下一行加载到字符串中?
(这就是您要使用的:std::getline(这个->文件,行)
)
你能给我一些建议吗?理想情况下,您可以将该类作为代码示例绘制出来。它可以用多种方式设计
这样你应该有一个
std::ifstream&
成员变量,虽然你也可以有一个指针类型,但是你需要做*\u stream,因为一旦你构建了解析器,在你打开文件之前,它可能处于一种非常无用的状态,我建议让您的用例看起来像这样:
Parser parser("/path/to/file");
std::pair<int> header = parser.getHeader();
while (parser.hasNext()) {
std::vector<int> tokens = parser.getNext();
}
parser.close();
如果将构造函数和成员函数分开,则可以将构造函数保留为默认值,因为文件
成员将被默认构造,为您提供一个与任何文件都不关联的文件流。然后,您可以使用Parser::open
将文件名转发到std::ifstream::open
,如下所示:
void Parser::open(std::string file_name)
{
file.open(file_name);
}
然后,是的,要从文件中读取行,您需要使用类似以下内容:
std::string line;
while (std::getline(file, line)) {
// Do something with line
}
当(!file.eof())
时,不要落入陷阱做得很好实际上,有一种替代方法可以将文件名提供给解析器
:您可以向它提供std::istream
。有趣的是,通过这种方式可以使用std::istream
的任何派生类,因此您可以向它提供数据,例如std::istringstream
,这使得编写单元测试更加容易
class Parser {
public:
explicit Parser(std::istream& is);
/**/
private:
std::istream& _stream;
/**/
};
接下来是迭代。在C++中,有一个<代码> > <代码>,后面跟着一个<代码>获取< /C>code>std::istream
支持迭代(使用输入迭代器),您可以完美地设计解析器,使其也能这样做。通过这种方式,您将获得与许多STL算法兼容的好处
class ParserIterator:
public std::iterator< std::input_iterator_tag, std::vector<int> >
{
public:
ParserIterator(): _stream(nullptr) {} // end
ParserIterator(std::istream& is): _stream(&is) { this->advance(); }
// Accessors
std::vector<int> const& operator*() const { return _vec; }
std::vector<int> const* operator->() const { return &_vec; }
bool equals(ParserIterator const& other) const {
if (_stream != other._stream) { return false; }
if (_stream == nullptr) { return true; }
return false;
}
// Modifiers
ParserIterator& operator++() { this->advance(); return *this; }
ParserIterator operator++(int) {
ParserIterator tmp(*this);
this->advance();
return tmp;
}
private:
void advance() {
assert(_stream && "cannot advance an end iterator");
_vec.clear();
std::string buffer;
if (not getline(*_stream, buffer)) {
_stream = 0; // end of story
}
// parse here
}
std::istream* _stream;
std::vector<int> _vec;
}; // class ParserIterator
inline bool operator==(ParserIterator const& left, ParserIterator const& right) {
return left.equals(right);
}
inline bool operator!= (parserIterator const& left, ParserIterator const& right) {
return not left.equals(right);
}
我将把getHeader
方法和实际解析内容留给您;) 如果不是从while循环调用,而是每次调用getNext()
,那么std::getline
的工作原理是否相同?@cls是的,它的工作原理完全相同。确保使用if(std::getline(file,line))
检查是否成功。
class ParserIterator:
public std::iterator< std::input_iterator_tag, std::vector<int> >
{
public:
ParserIterator(): _stream(nullptr) {} // end
ParserIterator(std::istream& is): _stream(&is) { this->advance(); }
// Accessors
std::vector<int> const& operator*() const { return _vec; }
std::vector<int> const* operator->() const { return &_vec; }
bool equals(ParserIterator const& other) const {
if (_stream != other._stream) { return false; }
if (_stream == nullptr) { return true; }
return false;
}
// Modifiers
ParserIterator& operator++() { this->advance(); return *this; }
ParserIterator operator++(int) {
ParserIterator tmp(*this);
this->advance();
return tmp;
}
private:
void advance() {
assert(_stream && "cannot advance an end iterator");
_vec.clear();
std::string buffer;
if (not getline(*_stream, buffer)) {
_stream = 0; // end of story
}
// parse here
}
std::istream* _stream;
std::vector<int> _vec;
}; // class ParserIterator
inline bool operator==(ParserIterator const& left, ParserIterator const& right) {
return left.equals(right);
}
inline bool operator!= (parserIterator const& left, ParserIterator const& right) {
return not left.equals(right);
}
ParserIterator Parser::begin() const {
return ParserIterator(_stream);
}
ParserIterator Parser::end() const {
return ParserIterator();
}