C ++: Как мне прочитать строку из файла .txt с неизвестным количеством переменных в каждой строке? - PullRequest
0 голосов
/ 18 февраля 2019

Я работаю над проектом, в котором мне нужно создать связанный список из заданного файла данных.Он содержит коды операций, имена, фамилии, адреса, города, штаты и почтовые индексы.Проблема в том, что в строках есть неизвестное количество пробелов, которые содержат адрес и город.Пример файла данных выглядит следующим образом:

A
Donald
Duck
1123 Appleberry Circle
Saint Cloud
MN
88084
A
Barry
Briches
112 New York Ave
Saint Cottleville
FL
78098

Я пытался использовать комбинацию:

infile >> FirstName >> LastName;
infile.getline(Address, 20);
infile.getline(City, 20);
infile >> State >> ZipCode;

, но когда я иду распечатать его, выводитсяочень странно.Любая помощь по этому вопросу будет принята с благодарностью.Весь код, который я сделал, прилагается.

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string.h>
#include "list.h"

using namespace std;

int main()
{
    ifstream infile("data2.txt", ios::in);
    ofstream outfile("output2.txt", ios::out);

    char opCode, fname[12], lname[12], address[20], city[12], state[4], 
    zip[6];

    MailListClass mailingList;

    infile >> ws >> opCode;

    while (opCode != 'Q')
    {
        switch (opCode)
        {
            case 'A' :  infile >> fname >> lname;
                        infile.getline(address, 20, '\n');
                        infile >> city >> state >> zip;
                        mailingList.addRecord(fname, lname, address, city, 
                        state, zip, outfile);
                        break;
            case 'P' :  mailingList.printRecord(outfile);
                        break;
        }
        infile >> ws >> opCode;
    }
    return 0;
}

Файлы структуры / классов .h и .cpp:

#ifndef LIST_H
#define LIST_H

#include <fstream>

using namespace std;

struct node
{
    char lname[12], fname[12], city[12], address[20], state[4], zip[6];
    node *next;
};

class MailListClass
{
    private:
        node *headPtr, *currPtr, *prevPtr;
    public:
        MailListClass();
        void addRecord(char fname[12], char lname[12], char address[20],
                            char city [12], char state[4], char zip[6],
                            ofstream &outfile);
        void printRecord(ofstream &outfile);
};

#endif 

list.cpp

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>

#include "list.h"

using namespace std;

MailListClass::MailListClass()
{
    headPtr = NULL;
    currPtr = NULL;
    prevPtr = NULL;
}

void MailListClass::addRecord(char fname[12], char lname[12], char address[20], char city[12],
                            char state[4], char zip[6], ofstream &outfile)
{
    node *tail = new node;
    tail->next = NULL;
    strcpy(tail->fname, fname);
    strcpy(tail->lname, lname);
    strcpy(tail->address, address);
    strcpy(tail->city, city);
    strcpy(tail->state, state);
    strcpy(tail->zip, zip);

    if (headPtr != NULL)
    {
        currPtr = headPtr;
        while (currPtr->next != NULL)
        {
            currPtr = currPtr->next;
        }
        currPtr->next = tail;
    }
    else
    {
        headPtr = tail;
    }
} 
void MailListClass::printRecord(ofstream &outfile)
{
    currPtr = headPtr;
    while (currPtr != NULL)
    {
        outfile << left << setw(12) << currPtr->lname;
        outfile << setw(12) << currPtr->fname;
        outfile << setw(20) << currPtr->address;
        outfile << setw(12) << currPtr->city;
        outfile << setw(6) << currPtr->state;
        outfile << setw(10) << currPtr->zip << endl;
        currPtr = currPtr->next;
    }
}

outfile должен выглядеть так:

Last Name    First Name    Address              City   State  Zip
Last Name    First Name    Address              City   State  Zip

, но с помощью getline () в моем коде мой вывод выглядит примерно так:

Last Name    First Name
                  Address#        AddressNameCityCity
Last Name    First Name
                  Address#        AddressName

1 Ответ

0 голосов
/ 18 февраля 2019

Боюсь, что подобные вопросы задавали очень часто.Тем не менее, вот мой ответ:

Я полагаю, что это неправильная концепция:

infile >> FirstName >> LastName;
infile.getline(Address, 20);

Это читает FirstName и LastName, но вопрос в том, где концы строкчитать?

Упрощенный пример, чтобы проиллюстрировать это:

#include <iostream>
#include <string>

int main()
{
  std::string name1, name2;
  std::cin >> name1 >> name2;
  std::cout << "name1: '" << name1 << "', name2: '" << name2 << "'\n";
  for (std::string line; std::getline(std::cin, line);) {
    std::cout << "next: '" << line << "'\n";
  }
  return 0;
}

Проверено на coliru с

Donald
Duck
1123 Appleberry Circle

, заданным в качестве ввода (echo -e):

$ g++ -std=c++17 main.cpp && echo -e "Donald\nDuck\n1123 Appleberry Circle\n" | ./a.out
name1: 'Donald', name2: 'Duck'
next: ''
next: '1123 Appleberry Circle'
next: ''

Живая демоверсия на coliru

Строка, прочитанная и напечатанная после Duck, пуста.Это потому, что operator<<(std::istream&, std::string&) не читает пробел (например, пробел, табуляция, конец строки), ограничивающий текст.Следовательно, концы строки после Donald и Duck остаются во входном буфере.После первого ввода строки (Donald >> name1) это не помешает.Следующий ввод (Duck >> name2) потребляет / пропускает пробелы до тех пор, пока не появится пробел.После второго ввода конец строки остается в буфере ввода до тех пор, пока не будет использован следующий вызов std::getline().

Существуют различные способы исправить это:

  1. Чтениевсе с std::getline() (и, возможно, используйте std::istringstream с операторами ввода для дальнейшей обработки буфера строки чтения).

  2. Поместите std::getline() после infile >> FirstName >> LastName;, чтобы пропуститьостаток строки.

  3. Использовать std::istream::ignore(), который

    Извлекает и удаляет символы из входного потока до и включая разделитель.

Приведенный выше пример исправлен с std::istream::ignore():

#include <iostream>
#include <string>

int main()
{
  std::string name1, name2;
  std::cin >> name1 >> name2;
  std::cin.ignore();
  std::cout << "name1: '" << name1 << "', name2: '" << name2 << "'\n";
  for (std::string line; std::getline(std::cin, line);) {
    std::cout << "next: '" << line << "'\n";
  }
  return 0;
}

Повторно протестировано на coliru:

$ g++ -std=c++17 main.cpp && echo -e "Donald\nDuck\n1123 Appleberry Circle\n" | ./a.out
name1: 'Donald', name2: 'Duck'
next: '1123 Appleberry Circle'
next: ''

Демонстрация в реальном времени на coliru


По поводу "часто задаваемых вопросов", вот некоторые другие вопросы:

Возможно, есть гораздо больше.Я нашел выше Google site:stackoverflow.com c++ input missing

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...