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