好的,以下是一种实现方法。基本上,我已经编写了一个std::getline
的实现,该实现接受谓词而不是字符。这样可以完成三分之二的工作:
template <class Ch, class Tr, class A, class Pred>
std::basic_istream<Ch, Tr> &getline(std::basic_istream<Ch, Tr> &is, std::basic_string<Ch, Tr, A>& str, Pred p) {
typename std::string::size_type nread = 0;
if(typename std::istream::sentry(is, true)) {
std::streambuf *sbuf = is.rdbuf();
str.clear();
while (nread < str.max_size()) {
int c1 = sbuf->sbumpc();
if (Tr::eq_int_type(c1, Tr::eof())) {
is.setstate(std::istream::eofbit);
break;
} else {
++nread;
const Ch ch = Tr::to_char_type(c1);
if (!p(ch)) {
str.push_back(ch);
} else {
break;
}
}
}
}
if (nread == 0 || nread >= str.max_size()) {
is.setstate(std::istream::failbit);
}
return is;
}
使用类似于这个函数对象的函数:
struct is_newline {
bool operator()(char ch) const {
return ch == '\n' || ch == '\r';
}
};
现在,唯一需要确定的是你是否以
'\r'
结尾,如果是,则如果下一个字符是
'\n'
,只需将其消耗并忽略即可。
编辑:为了将所有内容放入功能解决方案中,这里提供一个示例:
#include <string>
#include <sstream>
#include <iostream>
namespace util {
struct is_newline {
bool operator()(char ch) {
ch_ = ch;
return ch_ == '\n' || ch_ == '\r';
}
char ch_;
};
template <class Ch, class Tr, class A, class Pred>
std::basic_istream<Ch, Tr> &getline(std::basic_istream<Ch, Tr> &is, std::basic_string<Ch, Tr, A>& str, Pred &p) {
typename std::string::size_type nread = 0;
if(typename std::istream::sentry(is, true)) {
std::streambuf *const sbuf = is.rdbuf();
str.clear();
while (nread < str.max_size()) {
int c1 = sbuf->sbumpc();
if (Tr::eq_int_type(c1, Tr::eof())) {
is.setstate(std::istream::eofbit);
break;
} else {
++nread;
const Ch ch = Tr::to_char_type(c1);
if (!p(ch)) {
str.push_back(ch);
} else {
break;
}
}
}
}
if (nread == 0 || nread >= str.max_size()) {
is.setstate(std::istream::failbit);
}
return is;
}
}
int main() {
std::stringstream ss("this\ris a\ntest\r\nyay");
std::string item;
util::is_newline is_newline;
while(util::getline(ss, item, is_newline)) {
if(is_newline.ch_ == '\r' && ss.peek() == '\n') {
ss.ignore(1);
}
std::cout << '[' << item << ']' << std::endl;
}
}
我对原始示例进行了一些小修改。现在,
Pred p
参数是一个引用,以便谓词可以存储一些数据(特别是上次测试的最后一个
char
)。同样地,我使谓词
operator()
非常量,以便它可以存储该字符。
在主函数中,我有一个字符串在
std::stringstream
中,其中包含所有3个版本的换行符。我使用我的
util::getline
,如果谓词对象表示最后一个
char
是
'\r'
,那么我将
peek()
向前并忽略
1
个字符,如果它碰巧是
'\n'
。
std::endl
(使用in.get()
读取字符而非提取运算符),然后在第二次扫描中使用getline
。 - jonsca