OK、これがそれを行う1つの方法です。std::getline
基本的に、文字の代わりに述語を受け入れる実装を作成しました。これにより、そこまでの道のりの 2/3 が得られます。
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 つのバージョンすべてを含む文字列があります。私は my を使用util::getline
し、述語オブジェクトが最後char
が a'\r'
であると言う場合、先に進み、たまたま である場合は文字peek()
を無視します。1
'\n'