当输入行结尾混合时,std :: getline替代

spr*_*aff 7 c++ stdin stdio line-endings istream

我试图从a读取行,std::istream但输入可能包含'\r' 和/或 '\n',所以std::getline没有用.

很抱歉大喊,但这似乎需要强调......

该输入可以包含任一换行类型或两者.

有没有标准的方法来做到这一点?目前我正在努力

char c;
while (in >> c && '\n' != c && '\r' != c)
    out .push_back (c);
Run Code Online (Sandbox Code Playgroud)

......但这会跳过空白.D'哦!std::noskipws- 需要更多的摆弄,现在它是misehaving.

当然必须有更好的方法吗?!?

Eva*_*ran 4

好的,这是一种方法。基本上我已经实现了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;
}
Run Code Online (Sandbox Code Playgroud)

具有与此类似的函子:

struct is_newline {
    bool operator()(char ch) const {
        return ch == '\n' || ch == '\r';
    }
};
Run Code Online (Sandbox Code Playgroud)

现在,剩下的唯一事情就是确定您是否以 a 结尾'\r'...,如果是,那么如果下一个字符是 a '\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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我对原来的示例做了一些小改动。该Pred p参数现在是一个引用,以便谓词可以存储一些数据(特别是最后char测试的数据)。同样,我将谓词设为operator()非常量,以便它可以存储该字符。

在 main 中,我有一个字符串,其中std::stringstream包含所有 3 个版本的换行符。我使用 my util::getline,如果谓词对象说最后一个char是 a '\r',那么我会peek()向前并忽略1字符(如果它恰好是 )'\n'