C ++在eof()循环中使用迭代器进行标记

时间:2009-01-27 20:59:34

标签: c++ string iterator

我正在尝试调整这个答案

How do I tokenize a string in C++?

到我当前的字符串问题,涉及从文件读取到eof。

来自此源文件:

Fix grammatical or spelling errors

Clarify meaning without changing it

Correct minor mistakes

我想创建一个包含所有标记化单词的向量。示例:v ector<string> allTheText[0] should be "Fix"

我没有强调istream_iterator<std::string> end;的目的,但我包括原因是它在原始海报的答案上。

到目前为止,我已经得到了这个非工作代码:

vector<string> allTheText;
          stringstream strstr;
          istream_iterator<std::string> end;
          istream_iterator<std::string> it(strstr);

          while (!streamOfText.eof()){
                getline (streamOfText, readTextLine);
                cout<<readTextLine<<endl;

                stringstream strstr(readTextLine);
                // how should I initialize the iterators it and end here?

                }

编辑:

我将代码更改为

          vector<string> allTheText;
          stringstream strstr;
          istream_iterator<std::string> end;
          istream_iterator<std::string> it(strstr);

          while (getline(streamOfText, readTextLine)) {
               cout << readTextLine << endl;

        vector<string> vec((istream_iterator<string>(streamOfText)), istream_iterator<string>()); // generates RuntimeError


          }

得到一个RuntimeError,为什么?

1 个答案:

答案 0 :(得分:9)

在C ++中使用while (!….eof())循环被破坏了,因为当流进入错误状态时,永远不会退出循环!

相反,您应该直接测试流的状态。适应您的代码,这可能如下所示:

while (getline(streamOfText, readTextLine)) {
    cout << readTextLine << endl;
}

但是,您已经拥有流。为什么还把它放入字符串流?或者您是否需要逐行执行此操作?

您可以直接使用输入迭代器初始化矢量。无需构建字符串流,也无需使用copy算法,因为存在适当的构造函数重载。

vector<string> vec((istream_iterator<string>(cin)), istream_iterator<string>());

注意第一个参数附加的括号,这些括号是从函数声明中消除歧义所必需的。

编辑这个代码的一个小解释:

C ++提供了一种指定范围的统一方式。范围只是类型值的集合,不会详细说明如何存储这些值。在C ++中,这些范围表示为半开区间[ab [。这意味着一个范围由两个迭代器分隔(它们有点像指针但更通用;指针是一种特殊的迭代器)。第一个迭代器a指向范围的第一个元素。第二个,b,指向后面的最后一个元素。为什么落后?因为这允许非常容易地迭代元素:

for (Iterator i = a; i != b; ++i)
    cout << *i;

与指针一样,通过将*应用于它们,迭代器被取消引用。这会返回它们的值。

C ++中的容器类(例如vectorlist)有一个特殊的构造函数,可以轻松地将来自另一个范围的值复制到新容器中。因此,此构造函数需要两个迭代器。例如,以下内容将C样式数组复制到向量中:

int values[3] = { 1, 2, 3 };
vector<int> v(values, values + 3);

此处,values&values[0]同义,这意味着它指向数组的第一个元素。 values + 3,感谢指针算法,几乎等同于&values[3](但这是无效 C ++!)并指向虚拟元素阵列后面。

现在,我上面的代码与上一个示例完全相同。唯一的区别是我使用的迭代器的类型。我使用C ++提供的特殊迭代器类,而不是使用普通指针。此迭代器类以一种++ 前进输入流的方式包装输入流,*从流中读取下一个元素。元素的类型由type参数指定(因此在这种情况下为string)。

要使这项工作成为一个范围,我们需要指定一个开头和一个结尾。唉,我们不知道输入的结束(这是合乎逻辑的,因为当用户向控制台输入更多输入时,流的末尾实际上可能会随着时间而移动!)。因此,要创建虚拟 end 迭代器,我们不会将任何参数传递给istream_iterator的构造函数。相反,为了创建一个begin迭代器,我们传递一个输入流。然后创建一个指向流中当前位置的迭代器(此处为cin)。

我的上述代码在功能上与以下代码相同:

istream_iterator<string> front(cin);
istream_iterator<string> back;

vector<string> vec;

for (istream_iterator<string> i = front; i != back; ++i)
    vec.push_back(*i);

反过来,这相当于使用以下循环:

string word;
while (cin >> word)
    vec.push_back(word);