在输入流的开头匹配字符串

Matching a string at the beginning of a inputstream

本文关键字:字符串 开头 输入流      更新时间:2023-10-16

我实现了一个简单的输入流操纵符,将输入流中的下n个字符与给定字符串匹配。然而,我不确定这是否是最好的方法。有提示吗?

class MatchString {
private:
  std::string mString;
public:
  MatchString(const std::string &str) { 
    mString = str; 
  }
  std::istream& operator()(std::istream& is) const {
    // Allocate a string buffer, ...
    char *buffer = new char[mString.length()];
    // ... read next n chars into the buffer ...
    is.read(buffer, mString.length());
    // ... and compare them with given string.
    if(strncmp(buffer, mString.c_str(), mString.length())) {
      throw MismatchException(mString);
    }
    delete[] buffer;
    return is;
  }
};
inline MatchString match(const std::string &str) {
  return MatchString(str);
}
inline std::istream& operator>>(std::istream& is, const MatchString& matchStr) {
  return matchStr(is);
}
编辑:

可以根据user673679的建议实现使用匹配字符的解决方案:

class MatchString {
  ... 
  std::istream& operator()(std::istream& is) const {
    // Match the next n chars.
    std::for_each(mString.begin(), mString.end(),
      [&](const char c) {
        if(is.get() != c) {
          throw MismatchException(mString);
        }
      });
    return is;
  }
};

如果我不想消耗字符,我该如何实现呢?

编辑II:

这里是fjardon提到的另一个解决方案:

class MatchString {
  ...
  std::istream& operator()(std::istream& is) const {
    // Match the next n chars.
    if(std::mismatch(mString.begin(), mString.end(), 
            std::istreambuf_iterator<char>(is)).first != mString.end()) {
      throw MismatchException(mString);
    }
    return is;
  }
};

编辑III:

终于得到了一个工作函数,如果字符串不匹配,它将恢复消耗:

class MatchString {
  ...
  std::istream& operator()(std::istream& is) const {
    // Match the next n chars.
    std::streampos oldPos = is.tellg();
    if(std::mismatch(mString.begin(), mString.end(), 
            std::istreambuf_iterator<char>(is)).first != mString.end()) {
      is.seekg(oldPos);
      throw MismatchException(mString);
    }
    return is;
  }
};

不需要从流中分配和复制整个字符串,您可以一次只检查一个字符,从而完全避免分配缓冲区:

#include <iostream>
#include <sstream>
#include <string>
auto mString = std::string("foobar");
std::istream& match(std::istream& is) {
    for (auto c : mString)
        if (c != is.get())
            throw std::runtime_error("nope");
    return is;
}
int main()
{
    auto input = "foobarbaz";
    auto stream = std::istringstream(input);
    match(stream);
    std::cout << "done!" << std::endl;
}

您还应该为is.get()(或原始代码中的.read())添加错误检查。