2013-12-15 22 views
4

可以说我有一个外部while循环来读取每个字符并将其输出到控制台。我也想标记一个单词,如果它被发现,并通过使用peek方法,我可以找到一个单词的第一个实例。有没有办法在前面看到多个地方?例如,如果我在寻找“发薪日”这个词。我知道我可以将它输入到一个字符串中并搜索一个字符串,但我想以二进制模式读取文件,而且我不想从外部循环中取走任何值。如果我有一个读取方法的内部循环,那么这些值不会通过外部循环显示。peek()前方多个地方?

感谢

int main() 

ifstream strm; 
char *chr = new char; 

strm.open("mytext.txt",ios::out | ios::binary); 

while (strm.read(chr,1) 
{ 
    if (strm.peek() == 'p'; 
    { 
    cout << "found a word beginning with 'p'" << endl; 
    //what if I want to read multiple characters ahead. Peek will read only one. 
    } 

} 
+0

为什么使用动态分配? – Shoe

回答

5

您可以使用seekg方法将istream的内跳来跳去。

如果以二进制模式打开文件,可以使用tellg方法标记要跳转到的位置。

但是,如果以文本模式打开文件,则最好使用偏移量跳转(即strm.seekg(offset,strm.cur)),因为tellg和seekg会计算像newline这样的多字节字符在文本模式下。所以,如果你发现下一个字符是“p”,那么你可以阅读下一个n字符,然后跳回-n字符,如果它不是你想要的。

+0

谢谢。这两种解决方案都可以在这里工作,但是我之前从未真正使用过seekg,现在我已经发现它了,它完全符合我的需求。非常感谢。 – domonica

+0

@domonica:请注意,从长远来看,拥有合适的解析器通常是一个更好的解决方案,因为正确解析正确的错误处理,针对空白更改的稳健性以及安全转义意味着解析作业可以非常迅速地增长复杂性。更好的办法是使用像XML或JSON或CSV等格式良好的格式,而不是定义自己的格式,并使用良好的调试库来编写和加载它们。 –

4

有多种方法可以实现这一点,但传统方法只是在原始文件和“用户”功能之间添加一层:词法分析器。

例如,具有无限的缓冲词法分析:

class Lexer { 
public: 
    Lexer(std::istream& s): source(s) { this->read(); } 

    explicit operator bool() const { 
     return not queue.empty(); 
    } 

    Lexer& operator>>(std::string& s) { 
     assert(*this and "Test for readiness before calling this method"); 

     s = queue.front(); 
     queue.pop_front(); 

     if (queue.empty()) { this->read(); } 
     return *this; 
    } 

    std::string const* peek(size_t const i) { 
     while (source and queue.size() < i) { this->read(); } 
     return queue.size() >= i ? &queue[i] : nullptr; 
    } 

private: 
    void read() { 
     queue.emplace_back(); 
     if (not (source >> queue.back())) { queue.pop_back(); } 
    } 

    std::istream& source; 
    std::deque<std::string> queue; 
}; // class Lexer 

注:很明显,你可以完全限制词法分析器的缓冲,或使其缓冲东西比其他的话,等...主自定义类的优势在于:you指示语义!