peek() Multiple Places Ahead?

9.9k views Asked by At

Lets say I have an outer while loop to read each character and output it to console. I also want to flag a word if it is found and by using the peek method I can find the first instance of a word. Is there a way to peek multiple places ahead. For example, if I looking for the word "payday" . I know I can input this into a string and search a string, but I want to read files in binary mode and I don't want to take away any values from the outer loop. If I have an inner loop with a read method, those values are not then displayed via the outer loop.

Thanks

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.
  }

}
2

There are 2 answers

3
Lie Ryan On BEST ANSWER

You can use seekg method to jump around within the istream.

If you open your file in binary mode, you can use tellg method to mark the position to jump to.

However, if you open your file in text mode, it is better to jump with offset instead (i.e. strm.seekg(offset, strm.cur)), due to how multibyte characters like newline are counted by tellg and seekg in text mode. So if you detect that the next character is going to be "p", then you can read the next n character, then jump back -n character if it's not what you're looking for.

0
Matthieu M. On

There are multiple ways to achieve this, however the conventional one is simply to add one more layer between the original file and the "user" functions: a lexer.

For example, a Lexer with unlimited buffering:

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

Note: obviously, you could perfectly limit the buffering of the lexer, or make it buffer something else than words, etc... the main advantage of a custom class is that you dictate semantics!