Чтение входного файла в C++

Я хочу прочитать входной файл на С++, который включает следующие строки

- numberOfStates
- numberOfSymbols
- numberOfFinalStates
- list of final states (one per line)
- numberOfTransitions
- listOfTransitions (one per line. The transitions include two ints and one char)

Важно сказать, что числа разные в каждом входном файле. Мне приходится читать разное количество строк для каждого файла.

Это пример inputFile

10 
3 
1 
9 
12 
0 1 f 
0 3 f 
1 2 a 
2 9 f 
3 4 f 
3 8 f 
4 5 b 
5 6 f 
6 7 a 
8 9 f 

Как я могу объявить каждую переменную при чтении входного файла?

Вот тут я застрял.. не знаю, что делать

ifstream fin("inputFile.txt");

    int numberOfStates;
    int numberOfSymbols;
    int numberOfFinalStates;
    // I'm not sure how to declare the next variables because they will vary in size each time 


    while (fin >> numberOfStates >> numberOfSymbols >> numberOfFinalStates)
    {
        cout << numberOfStates << numberOfSymbols << numberOfFinalStates << endl;
    }

Я хотел бы работать с векторами, если это возможно.

Любые усилия или попытки с вашей стороны?

πάντα ῥεῖ 23.04.2019 18:33
Я хотел бы работать с векторами, если это возможно. Часто правильный выбор. Если нет, то это хорошая отправная точка.
user4581301 23.04.2019 18:38

ваша проблема Как я могу объявить каждую переменную или Как я могу прочитать файл?

bruno 23.04.2019 18:41

Этот формат файла установлен в камне? Для чего используется numberOfStates? Что обозначают int:s и char в таблице переходов?

Ted Lyngmo 23.04.2019 18:47

Я работаю с автоматами. В частности, пытаясь преобразовать NFA в DFA

Salo Charabati 23.04.2019 18:49

Если первый элемент в файле — numberOfStates («10»), почему вы читаете его в string name?

Beta 23.04.2019 18:50

... и в вашем примере numberOfTransitions это 12, но у вас есть только 10переходы.

Ted Lyngmo 23.04.2019 19:39
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
7
2 649
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

делает

while (fin >> name >> var1 >> var2 >> var3)
{
    cout << name << var1 << var2 << var3 << endl;
}

вы все время переписываете одни и те же переменные, вам нужно поместить значение в вектор, как вы говорите в своем вопросе

вам также необходимо проверить правильность каждого ввода, в настоящее время вы не обнаруживаете недопустимый ввод

и, конечно, вам нужно проверить, что вы открываете файл


Пример :

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

int main()
{
  std::ifstream fin("inputFile.txt");

  if (!fin.is_open()) {
    std::cerr << "cannot open inputFile.txt" << std::endl;
    return -1;
  }

  int numberOfStates, numberOfSymbols, numberOfFinalStates;

  if ((! (fin >> numberOfStates >> numberOfSymbols >> numberOfFinalStates))
      || (numberOfStates < 0)
      || (numberOfSymbols < 0)
      || (numberOfFinalStates < 0)) {
    std::cerr << "invalid file" << std::endl;
    return -1;
  }

  // final states are int, so memorize them in a vector of int
  // because their number is known I can size it rather than 
  // to 'push_back' each value
  std::vector<int> finalStates(numberOfFinalStates);

  for (int & ft : finalStates) {
    if (! (fin >> ft)) {
      std::cerr << "invalid file reading final states" << std::endl;
      return -1;
    }
  }

  int numberOfTransitions;

  if (!(fin >> numberOfTransitions) || (numberOfTransitions < 0))  {
    std::cerr << "invalid file reading the number of transitions" << std::endl;
    return -1;
  }

  // you say a transition contains 2 int and a char,
  // I define a structure for
  // i1 i2 and c are 'poor' names but I don't know their goal
  struct Transition {
    int i1, i2; 
    char c;
  };

  // the transitions saved in a vector
  std::vector<Transition> transitions(numberOfTransitions);

  for (Transition & tr : transitions) {
    if (!(fin >> tr.i1 >> tr.i2 >> tr.c)) {
      std::cerr << "invalid file reading transitions" << std::endl;
      return -1;
    }
  }

  // print to check

  std::cout << "numberOfStates = " << numberOfStates << std::endl;
  std::cout << "numberOfSymbols = " << numberOfSymbols << std::endl;
  std::cout << "numberOfFinalStates = " << numberOfFinalStates << "\nfinalStates:";
  for (int ft : finalStates) 
     std::cout << ' ' << ft;
  std::cout << std::endl;
  std::cout << "numberOfTransitions = " << numberOfTransitions
    << "\ntransitions:" << std::endl;
  for (const Transition & tr : transitions)
    std::cout << '\t' << tr.i1 << ' ' << tr.i2 << ' ' << tr.c << std::endl;

  return 0;
}

Компиляция и исполнение:

pi@raspberrypi:/tmp $ g++ -pedantic -Wextra -Wall a.cc
pi@raspberrypi:/tmp $ cat inputFile.txt
10 
3 
1 
9 
12 
0 1 f 
0 3 f 
1 2 a 
2 9 f 
3 4 f 
3 8 f 
4 5 b 
5 6 f 
6 7 a 
8 9 f 
pi@raspberrypi:/tmp $ ./a.out
invalid file reading transitions

Ошибка возникает из-за того, что файл содержит только 10 переходов, а не 12 ожидаемых, что приводит к изменению файла для ожидания 10 переходов:

pi@raspberrypi:/tmp $ ./a.out
numberOfStates=10
numberOfSymbols=3
numberOfFinalStates=1
finalStates: 9
numberOfTransitions=10
transitions:
    0 1 f
    0 3 f
    1 2 a
    2 9 f
    3 4 f
    3 8 f
    4 5 b
    5 6 f
    6 7 a
    8 9 f
pi@raspberrypi:/tmp $ 

Спасибо за Ваш ответ. Как мне поместить значение в вектор (или int)?

Salo Charabati 23.04.2019 19:07

Было бы здорово... Я застрял :(

Salo Charabati 23.04.2019 19:10

Если у вас есть переменное число чего-либо (определенное во время выполнения), вы используете массив:

std::vector<Type>   store;

Чтобы добавить элементы в вектор, вы используете push_back() (есть и другие методы, но давайте сделаем их простыми для новичков).

store.push_back(value);

Чтобы прочитать несколько вещей и сохранить их в векторе, вы просто используете цикл.

for(int loop = 0; loop < numberOfThings; ++loop) {
    Type  temp;
    fin >> temp;
    store.push_back(temp);
}

Так что же это за загадочное Type? Здесь вы используете подходящее имя типа. Для «Конечного состояния» это будет целое число (int), но для «Перехода» это будет тип класса, соответствующий (int/int/char).

 std::vector<int>   finalState;
 for(int loop = 0; loop < finalState; ++loop) {
     int nextFinal;
     find >> nextFinal;
     finalState.push_back(nextFinal);
 }

 ......
 std::vector<Transition>  Transitions;
 ... Just like above.

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

#include <iostream>
#include <fstream>
#include <vector>

struct transition {
    // rename the variables into something meaningful
    int int1;
    int int2;
    char a_char;

    friend std::istream& operator>>(std::istream&, transition&);
    friend std::ostream& operator<<(std::ostream&, const transition&);
};
// input stream function for reading one transition
std::istream& operator>>(std::istream& is, transition& t) {
    is >> t.int1 >> t.int2 >> t.a_char;
    return is;
}
// output stream function for writing one transition
std::ostream& operator<<(std::ostream& os, const transition& t) {
    os << t.int1 << " " << t.int2 << " " << t.a_char;
    return os;
}
//-----------------------------------------------------------------------------
struct entity {
    int numberOfStates;
    int numberOfSymbols;
    std::vector<int> finalStates;
    std::vector<transition> transitions;

    friend std::istream& operator>>(std::istream&, entity&);
    friend std::ostream& operator<<(std::ostream&, const entity&);
};
// read one entity from a stream
std::istream& operator>>(std::istream& is, entity& e) {
    int numberOfFinalStates, numberOfTransitions;
    int value;

    if (is >> e.numberOfStates >> e.numberOfSymbols >> numberOfFinalStates) {
        // read to value and put it in its vector
        while(numberOfFinalStates-- && is >> value) e.finalStates.push_back(value);

        if (is >> numberOfTransitions) {
            transition ttmp;
            // read to the temporary transition and put it in its vector
            while(numberOfTransitions-- && is >> ttmp) e.transitions.push_back(ttmp);
            // check that we got the number of values we wanted
            // and set the failbit if we didn't (should check size() of the vectors
            // instead)
            if (numberOfFinalStates != -1 || numberOfTransitions != -1)
                is.setstate(std::ios_base::failbit);
        }
    }
    return is;
}
// write one entity to a stream
std::ostream& operator<<(std::ostream& os, const entity& e) {
    os << e.numberOfStates << "\n" << e.numberOfSymbols << "\n" << e.finalStates.size() << "\n";
    for(const int fs : e.finalStates) os << fs << "\n";
    os << e.transitions.size() << "\n";
    for(const transition& t : e.transitions) os << t << "\n";
    return os;
}
//-----------------------------------------------------------------------------
int main() {
    std::ifstream fs("inputfile.txt");
    if (fs) {
        entity e;
        // stream the opened file into the entity 
        if (fs >> e) {
            std::cout << "loaded these values:\n";
            std::cout << e;
        } else {
            std::cerr << "failed loading file\n";
        }
    } else {
        std::cerr << "failed opening file\n";
    }
}

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

Mohammad 16.03.2020 02:37

@Mohammad Образец входного файла в вопросе OP:s должен работать.

Ted Lyngmo 16.03.2020 07:32

Извините, а что означает OP:s?

Mohammad 16.03.2020 23:56

@Mohammad О, здесь есть хорошее описание: Что такое OP при обращении к Stack Exchange?

Ted Lyngmo 17.03.2020 07:31

Отличный, оригинальный постер (OP) - я могу использовать онлайн-среду IDE для выполнения вашего примера кода выше. Это не принимает входной файл. Есть идеи? У меня ТОЛЬКО ноутбук с Windows 10.

Mohammad 17.03.2020 14:31

@Mohammad Кажется, у OP есть ошибка в исходных данных :-) Там сказано, что должно быть 12 переходов, но их только 10. Я поместил данные в std::istringstream вместо файла, чтобы вы могли видеть, что это работает: Демо

Ted Lyngmo 17.03.2020 14:48

Идеально. Я вижу, что это работает. Я также бесплатно установил VS2019 и успешно запустил код. Однако мне нужно будет изменить код таким образом, чтобы сохранить вывод в файле .csv/excel вместо выходного окна консоли. В дополнение к этому, можем ли мы читать данные из .csv вместо того, чтобы помещать данные в std::istringstream.

Mohammad 17.03.2020 16:01

@Mohammad Конечно, перегрузки operator<< и operator>> работают с любыми ostream/istream, например fstreams. Если ваши значения разделены запятыми, вам нужно будет адаптировать эти операторы, поскольку сейчас они работают со значениями, разделенными пробелами.

Ted Lyngmo 17.03.2020 16:10

Но как адаптировать эти операторы? Давайте создадим простой пример - например. отформатируйте отчет о случаях COVID19 :) Введите заголовки ниже: Страна, штаты, случаи США, Мичиган, 54 Италия, Ломбардия, 14649 …. Код должен прочитать это из файла .csv и записать результаты в файл .csv. Хорошо также кодировать вывод общего количества случаев. Не могли бы вы изменить приведенный выше код для этого более простого базового примера, пожалуйста.

Mohammad 17.03.2020 16:28

@Mohammad Здесь, на SO, должно быть много примеров того, как читать поток со значениями, разделенными запятыми, поэтому просто найдите его. Некоторые заботятся о строках в кавычках, а некоторые нет, поэтому вам нужно знать точный формат, который вам нужно поддерживать, а затем попытаться реализовать операторы для его поддержки. Если это не сработает, создайте вопрос здесь, в SO. Раздел комментариев не очень хорошее место для развернутых ответов. Плохое форматирование :-)

Ted Lyngmo 17.03.2020 16:36

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

Mohammad 17.03.2020 16:47

Это здесь, в stackoverflow.com/questions/38173857/…, возможно, стоит изменить. Можете ли вы применить это к синтаксису, который вы использовали в своем ответе выше, и разместили здесь измененный код, пожалуйста.

Mohammad 17.03.2020 17:07

@Mohammad Это было бы не очень хорошо, поскольку SO должен быть в формате вопросов и ответов. Я не могу опубликовать ответ на вопрос, который не был задан. Вы должны попытаться адаптировать его самостоятельно, и если вы застряли, опубликуйте вопрос о проблеме, на которой вы застряли. Если вы предоставите минимальный воспроизводимый пример и опишете, что вы ожидаете и что вместо этого произойдет, вы должны получить ответы очень быстро.

Ted Lyngmo 17.03.2020 17:18

Конечно, я уже создал новый вопрос с минимальным воспроизводимым примером из SO и описал проблему, с которой я столкнулся.

Mohammad 17.03.2020 17:37

Другие вопросы по теме