8

I'd like to read from a std::istream until a certain sequence of characters is found, i.e., I'd like to implement the following interface:

void read_until (std::istream &is, std::string_view needle);

Using std::istreambuf_iterator, I believe this is equivalent to a combination of std::search on a single-pass iterator. Unfortunately, the std::boyer_moore_searcher needs random-access iterators.

Are there any easy implementations of the above interface using the C++ standard library (and a bit of memory proportional to the size of sv), or do I have to code it myself?

Jive Dadson
  • 16,680
  • 9
  • 52
  • 65
levzettelin
  • 2,600
  • 19
  • 32
  • And where exactly are you reading this data into? Or are you simply going to advance the stream to that point? – Nicol Bolas Feb 26 '18 at 22:53
  • Simply advancing the stream. For example when parsing and I expect a certain keyword next, and I don't want to be very picky and just say "skip everything until you have found that sequence of characters". – levzettelin Feb 26 '18 at 23:03
  • Um, `std::search` works on any forward iterator. Now, your `istream` iterator isn't a forward iterator, but you don't need random access at least. – Yakk - Adam Nevraumont Oct 02 '18 at 18:05

1 Answers1

1
void read_until (std::istream &is, std::string_view needle) {
  if (needle.size()==0) return;
  std::string buff;
  buff.reserve(needle.size());
  auto it = std::find_if( std::istream_iterator<char>(is), std::istream_iterator<char>(), [&](char c) {
    buff.push_back(c);
    if (buff.size() < needle.size()) {
      return false;
    }
    if (buff == needle)
      return true;
    buff.erase(buff.begin());
    return false;
  });
}

that is the best I can do with std algorithms.

For optimization, using a circular buff might save a bit of work.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524