如何在C++中逐行迭代cin?

cpp*_*ner 32 c++ string line-processing

我想std::cin逐行迭代,将每一行作为a std::string.哪个更好:

string line;
while (getline(cin, line))
{
    // process line
}
Run Code Online (Sandbox Code Playgroud)

要么

for (string line; getline(cin, line); )
{
    // process line
}
Run Code Online (Sandbox Code Playgroud)

?这样做的正常方法是什么?

Jer*_*fin 72

由于UncleBen提出了他的LineInputIterator,我想我会添加更多替代方法.首先,一个非常简单的类充当字符串代理:

class line {
    std::string data;
public:
    friend std::istream &operator>>(std::istream &is, line &l) {
        std::getline(is, l.data);
        return is;
    }
    operator std::string() const { return data; }    
};
Run Code Online (Sandbox Code Playgroud)

有了这个,你仍然可以使用普通的istream_iterator阅读.例如,要将文件中的所有行读入字符串向量,您可以使用以下内容:

std::vector<std::string> lines;

std::copy(std::istream_iterator<line>(std::cin), 
          std::istream_iterator<line>(),
          std::back_inserter(lines));
Run Code Online (Sandbox Code Playgroud)

关键的一点是,当你正在阅读某些东西时,你指定一条线 - 但除此之外,你只需要字符串.

另一种可能性是使用标准库的一部分,大多数人几乎不知道存在,更不用说具有很多实际用途.当您使用operator >>读取字符串时,该流返回一个字符串,直到该流的区域设置所说的白色空格字符.特别是如果你做了很多面向行的工作,那么用ctype facet创建一个只能将new-line分类为white-space的语言环境会很方便:

struct line_reader: std::ctype<char> {
    line_reader(): std::ctype<char>(get_table()) {}
    static std::ctype_base::mask const* get_table() {
        static std::vector<std::ctype_base::mask> 
            rc(table_size, std::ctype_base::mask());

        rc['\n'] = std::ctype_base::space;
        return &rc[0];
    }
};  
Run Code Online (Sandbox Code Playgroud)

要使用它,您可以使用该方面使用区域设置来填充您要读取的流,然后只是正常读取字符串,而对于字符串,operator >>始终读取整行.例如,如果我们想要读取行,并按排序顺序写出唯一行,我们可以使用如下代码:

int main() {
    std::set<std::string> lines;

    // Tell the stream to use our facet, so only '\n' is treated as a space.
    std::cin.imbue(std::locale(std::locale(), new line_reader()));

    std::copy(std::istream_iterator<std::string>(std::cin), 
        std::istream_iterator<std::string>(), 
        std::inserter(lines, lines.end()));

    std::copy(lines.begin(), lines.end(), 
        std::ostream_iterator<std::string>(std::cout, "\n"));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

请记住,这会影响流中的所有输入.使用这几乎排除了将面向行的输入与其他输入混合(例如,从流中读取数字stream>>my_integer通常会失败).

  • 伙计们,他的名字是cppLearner.真. (4认同)
  • 我知道有一种方法可以指明哪个角色停止......我仍然希望有一种更简单的方法......我想知道这种语言是如何变得如此粗糙,有时让我感到难过.代理+1.易于编写,易于使用,更灵活. (3认同)

Unc*_*ens 8

LineInputIterator是我所拥有的(写作练习,但有一天可能有用)

#ifndef UB_LINEINPUT_ITERATOR_H
#define UB_LINEINPUT_ITERATOR_H

#include <iterator>
#include <istream>
#include <string>
#include <cassert>

namespace ub {

template <class StringT = std::string>
class LineInputIterator :
    public std::iterator<std::input_iterator_tag, StringT, std::ptrdiff_t, const StringT*, const StringT&>
{
public:
    typedef typename StringT::value_type char_type;
    typedef typename StringT::traits_type traits_type;
    typedef std::basic_istream<char_type, traits_type> istream_type;

    LineInputIterator(): is(0) {}
    LineInputIterator(istream_type& is): is(&is) {}
    const StringT& operator*() const { return value; }
    const StringT* operator->() const { return &value; }
    LineInputIterator<StringT>& operator++()
    {
        assert(is != NULL);
        if (is && !getline(*is, value)) {
            is = NULL;
        }
        return *this;
    }
    LineInputIterator<StringT> operator++(int)
    {
        LineInputIterator<StringT> prev(*this);
        ++*this;
        return prev;
    }
    bool operator!=(const LineInputIterator<StringT>& other) const
    {
        return is != other.is;
    }
    bool operator==(const LineInputIterator<StringT>& other) const
    {
        return !(*this != other);
    }
private:
    istream_type* is;
    StringT value;
};

} // end ub
#endif
Run Code Online (Sandbox Code Playgroud)

所以你的循环可以用算法替换(C++中另一个推荐的做法):

for_each(LineInputIterator<>(cin), LineInputIterator<>(), do_stuff);
Run Code Online (Sandbox Code Playgroud)

也许一个常见的任务是将每一行存储在一个容器中:

vector<string> lines((LineInputIterator<>(stream)), LineInputIterator<>());
Run Code Online (Sandbox Code Playgroud)


Tom*_*Tom 1

第一个。

两者的作用相同,但第一个更具可读性,而且您可以在循环完成后保留字符串变量(在第二个选项中,它包含在 for 循环范围内)

  • 将行保留在 for 范围内不是一件好事吗?在范围之外它没有多大用处,因为它最终会保留最后一行的值或其他内容? (7认同)