7

a から行を読み込もうとしてstd::istreamいますが、入力に'\r' and/or '\n'が含まれている可能性があるため、役に立ちstd::getlineません。

叫んで申し訳ありませんが、これは強調する必要があるようです...

入力には、改行タイプまたはその両方が含まれる場合があります。

これを行う標準的な方法はありますか?現時点では私はしようとしている

char c;
while (in >> c && '\n' != c && '\r' != c)
    out .push_back (c);

...しかし、これは空白をスキップします。ああ!std::noskipws--さらにいじる必要があり、今ではお粗末です。

きっともっと良い方法があるに違いない?!?

4

2 に答える 2

4

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'

于 2011-07-14T15:12:52.253 に答える
4

行を読む通常の方法はstd::getlineです。

編集: の実装std::getlineが壊れている場合は、次のような独自のものを書くことができます:

std::istream &getline(std::istream &is, std::string &s) { 
    char ch;

    s.clear();

    while (is.get(ch) && ch != '\n' && ch != '\r')
        s += ch;
    return is;
}

技術的には、これはおそらく壊れているという問題ではないことを付け加えておく必要がありstd::getlineます。基盤となるストリームの実装が壊れているためです。プラットフォームの行の終わりを示す文字から改行文字に変換するのはストリーム次第です。 . ただし、正確にどの部分が壊れているかに関係なく、実装が壊れている場合は、これで補うことができる場合があります (実装がひどく壊れている場合は、これが機能するかどうかを確認するのは困難です)。

于 2011-07-14T14:21:13.843 に答える