Игнорирование пустой строки во время fstream - PullRequest
0 голосов
/ 14 июля 2020

Написание программы для чтения текстового файла и сохранение его в структуре. Пример текстового файла:

chicken

dog

car


765

Когда в строке есть текст, он сохраняется в структуре. Я пробовал следующее:

getline(file, aLine);
Info.animalchicken = aLine;

getline(file, aLine);
Info.animaldog = aLine;

getline(file, aLine);
Info.car = aLine;

getline(file, aLine);
Info.number = aLine;

Я понял, что getline получает буквально каждую строку. Когда я запускаю это в своей программе, курица будет сохранена в struct Info.animalchicken. Следующая пустая строка будет сохранена в Info.animaldog. Собака будет храниться в Info.car и т. Д.

Я думаю, что здесь требуется элемент управления l oop, но я не могу придумать хороший. Как я могу игнорировать пустую строку, чтобы мой текст мог правильно войти в структуру?

Это моя структура

struct Info {
    string animalchicken;
    string animaldog;
    string car;
    int number;
}

Ответы [ 3 ]

1 голос
/ 14 июля 2020

Идея l oop, хотя и довольно примитивна, должна помочь; Самый простой способ - обернуть logi c в отдельную функцию:

std::string getlineFilterEmpty(std::istream& s) {
    std::string line;

    do {
        if (!s) {
            throw std::runtime_error("End of stream");
        }
        getline(s, line);
    } while(line.size() == 0);

    return line;
}

Тогда получить ваши значения так же просто, как:

Info.animalchicken = getlineFilterEmpty(file);
Info.animaldog = getlineFilterEmpty(file);
Info.car = getlineFilterEmpty(file);

Член number будет требуется преобразование строки в целое число, код которого вы найдете в другом месте на SO.

0 голосов
/ 16 июля 2020

Вот вариант добавления операторов потока и вспомогательной функции для пропуска пустых строк.

#include <iostream>
#include <limits>
#include <sstream>
#include <string>

struct Info {
    std::string animalchicken;
    std::string animaldog;
    std::string car;
    int number;
};

// a helper function to do getline but skip empty lines
std::istream& getline_with_content(std::istream& is, std::string& s) {
    while(std::getline(is, s)) if(not s.empty()) break;
    return is;
}

// an istream operator to read one Info
std::istream& operator>>(std::istream& is, Info& i) {
    getline_with_content(
        getline_with_content(
            getline_with_content(is,
                                 i.animalchicken),
            i.animaldog),
        i.car);

    is >> i.number;

    // ignore everything after the number until a newline appears:
    is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    return is;
}

// an ostream operator to print one Info
std::ostream& operator<<(std::ostream& os, const Info& i) {
    return os << i.animalchicken << '\n'
              << i.animaldog << '\n'
              << i.car << '\n'
              << i.number << '\n';
}

int main() {
    // an example istream with a lot of blank lines:
    std::istringstream file(
        "chicken\n\n"
        "dog\n\n"
        "car\n\n\n"
        "765\n");

    Info i;

    file >> i;      // read one Info from the stream

    std::cout << i; // print one Info
}

Демо

0 голосов
/ 14 июля 2020

logi c должен go что-то вроде,

Read a line. 
If read succeeded
    If line not empty
        Provide line
    Else
        Try again
Else
    Handle error

Переводя это в код и объединяя его в функцию для удобного повторного использования, мы получаем

std::string getNotEmptyLine(std::istream & in)
{
    while (true) // repeat forever!
    {
        std::string temp;
        std::getline(in, temp); // get a line
        if (in) // test the line
        {
            if (line.size() != 0) // line not empty
            {
                 return temp; //give it to caller
            }
        }
        else
        {
            // handle error. We'll throw an exception, but this isn't the best solution
            throw std::runtime_error("Couldn't read a line!"); 
        }
    }
}

Как и со всеми дословными переводами, над этим нужно немного поработать. Также было бы полезно, чтобы эта функция работала точно так же, как getline, чтобы вызывающий абонент мог использовать ее в качестве замены.

std::istream & getNotEmptyLine(std::istream & in, // stream to read
                               std::string & line, // somewhere to put the string 
                               char  delim = '\n') // allow different delimiters
{
    while (true) // repeat forever!
    {
        if (std::getline(in, line, delim)) // get a line right in line and test that we got it.
        {
            if (line.size() != 0) // line not empty
            {
                 break; // success. exit.
            }
        }
        else
        {
            // line will contain whatever this implementation of `getline` puts or 
            // leaves in the string on failure.
            break; // fail. Let the caller decide what to do
        }
    }
    return in;
}

Использование:

Info info;
std::string aLine;
if (getNotEmptyLine(in, info.animalchicken) &&
    getNotEmptyLine(in, info.animaldog) &&
    getNotEmptyLine(in, info.car) &&
    getNotEmptyLine(in, aLine))
{
    info.number = std::stoi(aLine);
}
else
{
    // handle error
}

Примечание. даже это может быть слишком упрощенно c. Он не может обрабатывать строку, содержащую только пробелы. Единичное неуместное и почти невидимое пространство нанесет ущерб хаво c. Если это вызывает беспокойство, добавьте еще logi c к if (line.size() != 0)

.
...