匹配输入流开头的字符串

时间:2015-09-24 11:14:22

标签: c++ string c++11

我已经实现了一个简单的输入流操纵器,以匹配输入流中的下一个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;
  }
};

1 个答案:

答案 0 :(得分:0)

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

#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())。