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

标签 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

我想创建一个包含所有标记化单词的 vector 。示例: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,为什么?

最佳答案

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

相反,您应该直接测试流的状态。适应您的代码,这可能看起来像这样:

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

但是,您已经了一个流。为什么还要将它放入字符串流中?或者您是否出于任何原因需要逐行执行此操作?

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

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

请注意第一个参数周围的额外括号,这是从函数声明中消除歧义所必需的。

编辑 一段简短的解释这段代码的作用:

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

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

与指针一样,通过对迭代器应用 * 可以解除引用。这将返回它们的值。

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

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

此处,values&values[0] 同义,表示它指向数组的第一个元素。 values + 3,由于指针运算,几乎等同于&values[3](但这无效 C++!) 并指向数组后面的虚拟元素。

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

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

关于C++ 在 eof() 循环中使用迭代器进行分词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/485230/

相关文章:

c++ - 尝试在 OSX 而不是 Linux 中创建多个帧缓冲区对象时出现问题

c# - 合并字符串的最佳方法是什么?

java - 迭代器中没有这样的元素

c++ - 为什么这里不考虑 std::begin/end?

c++ - 为什么设置套接字发送/接收缓冲区大小大于 sysctl max 时没有错误?

c++ - 哪些 C++ 编译器会自动定义 size_t 而无需包含 header ?

c++为什么在将字符串文字传递给函数时分配内存?

ruby-on-rails - Ruby on Rails - 除非多个条件

c++ - 使用迭代器排序列表不会对最后一个元素 C++ 进行排序

c++ - 如何在发出 commandFinished() 信号时检查状态