Я хочу прочитать входной файл на С++, который включает следующие строки
- 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;
}
Я хотел бы работать с векторами, если это возможно.
ваша проблема Как я могу объявить каждую переменную или Как я могу прочитать файл?
Этот формат файла установлен в камне? Для чего используется numberOfStates? Что обозначают int:s и char в таблице переходов?
Я работаю с автоматами. В частности, пытаясь преобразовать NFA в DFA
Если первый элемент в файле — numberOfStates («10»), почему вы читаете его в string name?
... и в вашем примере numberOfTransitions это 12, но у вас есть только 10переходы.





делает
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)?
Было бы здорово... Я застрял :(
Если у вас есть переменное число чего-либо (определенное во время выполнения), вы используете массив:
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 Образец входного файла в вопросе OP:s должен работать.
Извините, а что означает OP:s?
@Mohammad О, здесь есть хорошее описание: Что такое OP при обращении к Stack Exchange?
Отличный, оригинальный постер (OP) - я могу использовать онлайн-среду IDE для выполнения вашего примера кода выше. Это не принимает входной файл. Есть идеи? У меня ТОЛЬКО ноутбук с Windows 10.
@Mohammad Кажется, у OP есть ошибка в исходных данных :-) Там сказано, что должно быть 12 переходов, но их только 10. Я поместил данные в std::istringstream вместо файла, чтобы вы могли видеть, что это работает: Демо
Идеально. Я вижу, что это работает. Я также бесплатно установил VS2019 и успешно запустил код. Однако мне нужно будет изменить код таким образом, чтобы сохранить вывод в файле .csv/excel вместо выходного окна консоли. В дополнение к этому, можем ли мы читать данные из .csv вместо того, чтобы помещать данные в std::istringstream.
@Mohammad Конечно, перегрузки operator<< и operator>> работают с любыми ostream/istream, например fstreams. Если ваши значения разделены запятыми, вам нужно будет адаптировать эти операторы, поскольку сейчас они работают со значениями, разделенными пробелами.
Но как адаптировать эти операторы? Давайте создадим простой пример - например. отформатируйте отчет о случаях COVID19 :) Введите заголовки ниже: Страна, штаты, случаи США, Мичиган, 54 Италия, Ломбардия, 14649 …. Код должен прочитать это из файла .csv и записать результаты в файл .csv. Хорошо также кодировать вывод общего количества случаев. Не могли бы вы изменить приведенный выше код для этого более простого базового примера, пожалуйста.
@Mohammad Здесь, на SO, должно быть много примеров того, как читать поток со значениями, разделенными запятыми, поэтому просто найдите его. Некоторые заботятся о строках в кавычках, а некоторые нет, поэтому вам нужно знать точный формат, который вам нужно поддерживать, а затем попытаться реализовать операторы для его поддержки. Если это не сработает, создайте вопрос здесь, в SO. Раздел комментариев не очень хорошее место для развернутых ответов. Плохое форматирование :-)
Согласен с вами по подробным ответам в поле для комментариев и плохому форматированию! К сожалению, многие примеры не являются общими, аккуратными и чистыми, насколько я искал. Моя цель состояла в том, чтобы просто создать дополнительную ценность для вашего ответа на этот вопрос выше, запросив исправленную версию кода. Спасибо, Тед.
Это здесь, в stackoverflow.com/questions/38173857/…, возможно, стоит изменить. Можете ли вы применить это к синтаксису, который вы использовали в своем ответе выше, и разместили здесь измененный код, пожалуйста.
@Mohammad Это было бы не очень хорошо, поскольку SO должен быть в формате вопросов и ответов. Я не могу опубликовать ответ на вопрос, который не был задан. Вы должны попытаться адаптировать его самостоятельно, и если вы застряли, опубликуйте вопрос о проблеме, на которой вы застряли. Если вы предоставите минимальный воспроизводимый пример и опишете, что вы ожидаете и что вместо этого произойдет, вы должны получить ответы очень быстро.
Конечно, я уже создал новый вопрос с минимальным воспроизводимым примером из SO и описал проблему, с которой я столкнулся.
Любые усилия или попытки с вашей стороны?