C++ 在C+;中实现逐行文件解析器时遇到问题+;

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

我很难在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.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();
    }