У меня есть файл данных в текстовом формате. У него 2 колонны, во-первых, бесполезно, чтобы я мог игнорировать это, а во-вторых, это то, что мне нужно. В столбце есть разные значения в каждой строке, такие как строка, число с плавающей запятой и т. Д. Для некоторых вычислений мне нужно использовать только члены этого столбца. Я пошел по этому пути, сначала объявил массив с плавающей точкой и прочитал значения и сохранил массив с «>>» основная команда.
Проблема в том, что когда пришла строка с плавающей точкой, функция чтения работает как неработающая. Он читает не плавающие значения как «0» и сохраняет их как таковые. Это нормально, но после этого считывает целые значения как «0», даже если это было число с плавающей точкой.
Datafile.txt (пример)
aa 1.1
bb 2.2
cc 3.0
dd somestring
ee 4.3
ff 4.9
Код (пример)
do
{
dfile >> a >> dat[i];
ofile << dat[i]<<endl;
cout << dat[i]<<endl;
i++;
}while(dfile.eof());
Выходной файл (пример)
1.1
2.2
3.0
0
0
0
..goes
Я думал о двух способах решения проблемы. Первый — пропустить строки без плавающего. Второй — чтение строки за период. Потому что значения с плавающей запятой перечислены в последовательности.
Сначала прочитайте строку, а затем попытайтесь преобразовать в число:
std::string maybeNumber;
while (dfile >> a >> maybeNumber)
{
std::istringstream is(maybeNumber);
float number = 0.0f;
if (is >> number)
{
dat[i] = number;
i++;
}
}
(Вы не хотите использовать eof
, Каждый думает, что хочет использовать eof
, но это почти всегда не то, что им нужно. Увидеть этот вопрос для деталей.)
Это нормально, но после этого считывает целые значения как «0», даже если это было число с плавающей точкой.
Вы не показали свой полный код, но похоже, что входной поток находится в состоянии ошибки после первого не разбираемого числа с плавающей запятой, поэтому он вообще перестает читать.
Что касается решения проблемы, прочитайте каждую строку как std::string
затем разделите строку на std::vector<std::string>
, Если вектор не содержит двух элементов или если второй не является double
, ничего не делать, иначе обработать строку.
Что-то вроде этого:
std::string line;
while (std::getline(dfile, line))
{
auto const elements = parse(line);
if (size(elements) == 2 && is_double(elements[1]))
{
// process
}
}
Теперь, когда вы решили проблему на более высоком уровне абстракции, все, что вам нужно сделать, это реализовать что-то вроде parse
а также реализовать что-то вроде is_double
(делить & завоевать).
Также обратите внимание, что тип C ++ по умолчанию с плавающей точкой double
и не float
, Если есть сомнения, используйте double
,
Я бы использовал такой алгоритм:
Для каждой строки в файле:
с помощью GetLine а также regex_token_iterator
#include <regex>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
std::vector<float> v;
std::regex reg("-?\\d+(\\.\\d+)?");
const char* filename="myfile.txt";
std::ifstream ifs(filename,std::ios::binary);
for(std::string s;std::getline(ifs,s);)
for(std::sregex_token_iterator rgi(s.begin(),s.end(),reg);rgi!=std::sregex_token_iterator();++rgi)
v.push_back(std::stof(rgi->str());
std::copy(v.begin(),v.end(),std::ostream_iterator<float>(std::cout," ");
return 0;
}