【问题标题】:How to properly use std::getline function如何正确使用 std::getline 函数
【发布时间】:2016-04-13 10:07:12
【问题描述】:

我有一个文件,其中包含某人的姓名、他们所在的课程以及名册

例如。约翰·史密斯:11:F12

目前的输出是这样的

George.Clooney

Jennifer.Lawrence

Kevin.Bacon


15:S13

15:F15

15:F15

如何去掉课程参考中的冒号?我希望它看起来像这样

15S13

我的代码

struct studentinfo
{
     string name;
     string classref;
};

void readNumbers(istream &input, char *argv[], int argc)
{

    string program = argv[0];
    string text = argv[1];
    studentinfo array[10];
    string name;
    int i=0;

    if(text=="students.txt"){   
        while(!getline(input, array[i].name, ':').eof()){
            input >> array[i].classref; 
            i++;
   }

    for(int j=0; j < i; j++){ 
        cout<< array[j].name << endl;
    }

    for(int i=0; i < 10; i++){ 
        cout << array[i].classref << endl;
    }       
}

【问题讨论】:

  • 这真的取决于使用模式,不是吗?您多久执行一次与更新相关的查询,您执行哪种查询等。举个极端的例子,如果您几乎从不查询,而只更新,您可能会使用一个向量,最后将内容附加到该向量。跨度>
  • 真的,这取决于您要存储它的目的 - 您是在询问持久性还是内部存储?你的项目大吗?你会比查询更频繁地更新它吗?你有一些自然键吗?
  • @Lauren 您应该提出新问题,而不是编辑现有问题以完全改变它的要求。您现在完全断章取义地回答了我的问题。通过提出更多问题,您将获得更高的评分,因此这样做也符合您的利益。

标签: c++ getline


【解决方案1】:

这是这个问题多次迭代的答案,所以它可能看起来与上面的问题有点不协调。


问题是您正在使用std::getline 读取“:”字符。然后,您使用重载的运算符&gt;&gt;std::string 进行另一次读取到相同的字符串name 覆盖它。这次它读到了行尾。

在调用std::getline 之后,变量name 包含John.Smith,然后您立即通过执行input &gt;&gt; name; 覆盖该值。这与getline 基本相同,但无法指定分隔符。字符串name 然后包含11:F12,您将其复制到数组中以供稍后显示。

我认为您对getline 工作方式的困惑在这里可以看出,您不需要使用&gt;&gt; 读取名称值,它已经在字符串name 中。您只需要阅读该行的其余部分并将其丢弃。我建议您阅读std::getline 的在线参考,以更好地掌握它的工作原理。

要解决您的问题,您可以执行以下任何操作。

  1. 在将name 复制到数组并丢弃该值后,再执行一次“getline”或“>>”,这样它会清除该行的其余部分,然后在循环的@987654339 中读取下一个名称@ 称呼。实现这一点的一个稍微笨拙的方法是将input &gt;&gt; name; 移动到将name 添加到数组的行之后。
  2. 读取整行,不带分隔符,然后查找(使用 find 成员函数)第一次出现的 ':' 并获取该字符之前的子字符串(使用 substr 成员函数)。
  3. 使用名称和类成员定义一个结构并将这两个值读入结构。这样,您就可以故意从文件中读取这两个值。如果您不关心课程字符串,这可能是矫枉过正。

一些代码或多或少符合我的建议。

#include<fstream>
#include<iostream>
#include<string>

using namespace std;

void readNumbers(istream &input)
 {
    string array[10];
    string name;
    string garbage;
    int i=0;

    while(getline(input, name, ':'))
    {           
        array[i]=name;
        i++;

        input >> garbage;
    }

    for(int i=0; i<10; i++) cout<< array[i] << '\n';
 }

 void readNumbers2(istream &input)
 {
    string array[10];
    string ln;
    int i=0;

    while(getline(input, ln))
    {           
        size_t colpos = ln.find(':'); 

        if(colpos != string::npos)
        {
            array[i]=ln.substr(0, colpos);
            i++;
        }            
    }

    for(int i=0; i<10; i++) cout<< array[i] << '\n';
 }

 struct studentinfo
 {
     string name;
     string classref;
 };

 void readNumbers3(istream &input)
 {
    studentinfo array[10];
    string name;
    int i=0;

    while(getline(input, array[i].name, ':'))
    {
        input >> array[i].classref;
        i++;
    }

    for(int j=0; j < i; j++) 
        cout<< "name=" << array[j].name << '\n';
 }

int main()
{
    std::ifstream f("students.txt");

    readNumbers(f);
}

当然这不处理边缘情况,例如文件中的空行或超出数组,但它演示了std::getline 的使用。我还建议您查看 std::vectorstd::array 来保存您的字符串并使用迭代器或基于范围的 for 循环来打印值。

要从字符串中删除冒号,您可以使用以下方法。使用find 查找冒号字符索引和string::erase 的单个迭代器重载以删除该位置的字符。

void charerase()
{
    std::string s("15:F15");

    std::cout << s << '\n';

    size_t cpos = s.find(':');

    if(cpos != std::string::npos)
    {
        s.erase(s.begin() + cpos);
    }

    std::cout << s << '\n';
}

为此,您需要包含标题&lt;iterator&gt;

【讨论】:

    猜你喜欢
    • 2021-04-22
    • 2014-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-23
    • 2012-09-21
    • 2020-10-21
    相关资源
    最近更新 更多