如何正确使用std :: getline函数

时间:2016-04-13 10:07:13

标签: c++ getline

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

离。和John.Smith: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;
    }       
}

1 个答案:

答案 0 :(得分:2)

这是这个问题的几次迭代的答案,因此上面提到的内容可能看起来有点不合适。

问题是您使用std::getline来阅读&#39;:&#39;字符。然后使用重载的运算符>>作为std::string,再次读取相同的字符串name覆盖它。这次它读到行尾。

调用std::getline后,变量name包含John.Smith,然后您通过执行input >> name;立即覆盖该值。这与getline基本相同,没有指定分隔符的能力。然后,字符串name包含11:F12,您可以将其复制到数组中以便稍后显示。

我认为您对getline的工作原理感到困惑,但您并不需要使用>>来读取名称值,因为它已经在字符串name中。你只需要阅读剩下的部分并丢弃它。我建议您阅读std::getline的在线参考资料,以便更好地了解其工作原理。

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

  1. 做另一个&#39; getline&#39;或者&#39;&gt;&gt;&#39;将name复制到数组并丢弃该值后,它会清除该行的其余部分,然后在循环getline调用中读取下一个名称。实现此目的的一种稍微晦涩的方法是在将input >> name;添加到数组的行之后移动name
  2. 读取整行,没有分隔符,然后找到(使用find成员函数)第一次出现&#39;:&#39;并使用一个子字符串直到该字符(使用substr成员函数)。
  3. 定义名称为&amp;的结构。类成员并将这两个值读入结构中。这样您就可以故意从文件中读取这两个值。如果你不关心课程字符串,这可能会有点过分。
  4. 有些代码或多或少地符合我的建议。

    #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以保留字符串并使用迭代器或基于范围的循环来打印值。

    要从字符串中删除冒号,可以使用以下方法。使用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';
    }
    

    为此,您需要添加标题<iterator>