C++: прочитать из файла только числа в двумерный или одномерный контейнер
Допустим, имеется текстовый файл 1.txt
в папке исходника с таким содержимым:
1 2 3 4.5 4 куку 123 строка будет пропущена 1e4 222
Прочитаем из него числа double
, положим в вектор векторов и выведем, что получилось.
При чтении будем игнорировать строку, в которой не удалось распознать хотя бы одну лексему как число double
(нетрудно добавить вывод номеров таких строк для контроля ошибок).
Пример проверен в консоли Visual Studio 2019.
#include <iostream> #include <iomanip> #include <vector> #include <string> #include <sstream> #include <fstream> using namespace std; int main() { ifstream f("1.txt"); //из текущей папки if (!f) { cout << "No file!"; return 1; } //любое количество строк с любым количеством чисел читаем в вектор векторов vector <vector<double> > data; string line; do { getline (f, line, '\n'); istringstream reader(line); vector <double> lineData; double val; string::const_iterator i = line.begin(); bool error = false; do { double val; reader >> val; if (reader.fail()) { error = true; break; //пропуск строк с не-числами } lineData.push_back(val); } while (!reader.eof()); if (!error) data.push_back(lineData); } while (!f.eof()); //что вышло cout.precision (2); for (int i = 0; i < data.size(); i++) { for (int j = 0; j < data[i].size(); j++) { cout << fixed << setw(8) << data[i][j] << " "; } cout << endl; } return 0; }
А получилось вот что:
1.00 2.00 3.00 4.50 4.00 10000.00 222.00
Теперь легко проверить, что данные отвечают нашим требованиям, например, все вложенные вектора содержит одинаковое количество чисел (если есть такое требование).
Допустим, показанный выше подход сложноват. Как ещё можно поступить?
Именно в таких случаях программисты и придумывают форматы данных, соблюдать которые должен уже тот, кто готовит данные для программы.
Что мешает нам потребовать, чтобы в начале файла располагались 2 числа, указывающие размерность матрицы, и писать потом уже вполне школьный код?
Файл 1.txt
станет, например, таким:
2 2 1 2.5 3 4
А пример таким:
#include <iostream> #include <iomanip> #include <vector> #include <string> #include <sstream> #include <fstream> using namespace std; int main() { ifstream f("1.txt"); //из текущей папки if (!f) { cout << "No file!"; return 1; } double **data; int n, m; f >> n >> m; if (f.fail() || n < 1 || m < 1) { cout << "Bad size or not found 2 numbers"; return 2; } data = new double * [n]; if (!data) { cout << "No memory"; return 3; } for (int i = 0; i < n; i++) { data[i] = new double [m]; if (!data[i]) { cout << "No memory"; return 4; } } //читаем и сразу выводим, что вышло cout.precision(2); bool error = false; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { f >> data[i][j]; if (f.fail()) { error = true; data[i][j] = 0; f.clear(); } cout << fixed << setw(8) << data[i][j] << " "; } cout << endl; } if (error) cout << "There is error(s) in file, please check it!"; return 0; }
Заодно ловим самым примитивным образом ошибки в данных, но, хотя бы, не зависим от лишнего пробела между числами и т.п.
В коде ниже мы читаем просто вектор элементов double
из файла data.txt
с проверкой корректности чисел:
#include <iostream> #include <fstream> #include <vector> #include <string> using namespace std; int main() { vector <double> data; double val; ifstream f ("data.txt"); if (!f) { cout << "Can't open file"; return 1; } do { f >> val; if (f.fail()) { f.clear(); while (1) { char c = f.get(); if (c == ' ' || c == '\n' || f.eof()) break; } } else { data.push_back(val); } } while (!f.eof()); f.close(); cout << endl; for (int i = 0; i < data.size(); i++) cout << data[i] << " "; return 0; }
с таким файлом data.txt
:
1 1.5 2 1e900 coocoo bad 123
15.05.2020, 22:44 [1517 просмотров]