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

У меня есть текстовый файл, расположенный как:

Diam
<D>          4.2
05:21:26 02:Apr:2012
Point 1
<X>       2
<Y>       5
<Z>       6
Point 2
<X>       4
<Y>       2
<Z>       0
Point 3
<X>       4
<Y>       1
<Z>       2
End
End

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

#include <iostream>
#include <string>

using namespace std;

int main()
{
//count number of data points in file (only count lines starting with P)
const char FileName[] = "myfile.txt";
int num = 0.;
string line;
ifstream file;
file.open (FileName);
while(file.eof() == false)
{
getline(file, line);
if (line[0]=='P')  num++;
}
file.close();

return 0;
}

Это дает мне правильное количество баллов (хотя улучшения в коде приветствуются), и, во-вторых, мне нужно прочитать координаты x, y и z и игнорировать все остальное.
Не знаете, как это сделать, какие-либо предложения?

Заранее спасибо!

РЕДАКТИРОВАТЬ:

Спасибо всем за отличные идеи и ответы! Капитан Обвлиус дал отличный ответ, и я хочу посмотреть, можно ли его немного адаптировать.

Итак, получается, что файл .txt будет иметь формат:

Diam
<D>          4.2      5    6    4   2
05:21:26 02:Apr:2012
Point 1
<X>       2   5    6    4   2
<Y>       5   4    4    8   3
<Z>       6   7    6    0   2
Point 2
<X>       4   2    6    4   2
<Y>       2   3    5    8   4
<Z>       0   7    6    3   2
Point 3
<X>       4   0    6    2   2
<Y>       1   5    6    7   4
<Z>       2   0    6    5   3
End
End

Опять же, мне нужен только первый столбец значений, все остальное после этого можно отбросить.
я использовал int для простоты, но цифры будут double,
После прочтения я пытаюсь поместить значения в броненосец матрица, так что моя матрица выглядит так:

cout << matrix << endl;
2 5 6
4 2 0
4 1 2

Итак, я изменил решение Captain Obvlious для размещения данных в матрице:

#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
#include <sstream>
#include <stdexcept>
#include <armadillo>

using namespace std;
using namespace arma;

int main()
{
mat matrix(3,3);  //here is where I set the size of the matrix,
//different files have different number of points,
//that's why I use my counting points code to set the size.
const char FileName[] = "myfile.txt";
string line;
ifstream file;
file.open (FileName);

for(;;)
{
getline(file, line);
if( file.eof() ) {
break;
}

if (line.size() && line[0]=='P')
{
// Change "int" to "double" if necessary.
struct { double  x, y, z; } data;

for(int i = 0; i < 3; i++)
{
getline(file, line);
if(line.size() > 3 && line[0] == '<' && line[2] == '>')
{
string::value_type pointElement = line[1];

// skip spaces and process data here to get the value
string::size_type offset = line.find(' ');
if(string::npos == offset)
{
throw invalid_argument("Invalid data format");
}

stringstream sline(line.substr(offset));
int value;
if(!(sline >> value))
{
throw invalid_argument("invalid data format");
}switch(pointElement)
{
case 'X':   data.x = value; break;
case 'Y':   data.y = value; break;
case 'Z':   data.z = value; break;
default:
// error in data format
throw invalid_argument("invalid data format");
}
}
else
{
// error in data format
throw invalid_argument("invalid data format");
}
}

// Do something with the values in data
cout
<< "point[x=" << data.x
<< ", y=" << data.y
<< ", z=" << data.z
<< "]" << endl;
// place data in matrix
// need to loop over k where k is the row of the matrix
matrix(k,0) = data.x; // format is matrix(rows,columns)
matrix(k,1) = data.y;
matrix(k,2) = data.z;
}
}
file.close();

return 0;
}

Не уверен, где разместить цикл над k, который устанавливает строку матрицы для распределения значений.
Извините за супер длинный пост, и заранее благодарю за любую помощь. На мой взгляд, это довольно полезный материал для будущего использования.

2

Решение

Вам необходимо обработать каждую строку данных точки по отдельности и сохранить их в некотором типе структуры данных, чтобы их можно было обрабатывать после загрузки X, Y и Z. Вы должны также включить некоторый дополнительный код проверки, иначе вы, вероятно, введете неопределенное поведение. Есть несколько способов сделать это, некоторые заставят вас дублировать код, другие сосредоточатся на присвоении данных после их обработки.

Приведенное ниже решение учитывает как проверку, так и тот факт, что данные должны быть прочитаны из 3 отдельных строк. Он не идеален и ожидает, что файл «myfile.txt» будет в точном формате. Он использует исключения для обработки ошибок в формате данных и добавляет структуру данных для сохранения данных во время их загрузки.

#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
#include <sstream>
#include <stdexcept>

using namespace std;

int main()
{
const char FileName[] = "myfile.txt";
string line;
ifstream file;
file.open (FileName);

for(;;)
{
getline(file, line);
if( file.eof() ) {
break;
}

if (line.size() && line[0]=='P')
{
// Change "int" to "double" if necessary.
struct { int x, y, z; } data;

for(int i = 0; i < 3; i++)
{
getline(file, line);
if(line.size() > 3 && line[0] == '<' && line[2] == '>')
{
string::value_type pointElement = line[1];

// skip spaces and process data here to get the value
string::size_type offset = line.find(' ');
if(string::npos == offset)
{
throw invalid_argument("Invalid data format");
}

stringstream sline(line.substr(offset));
int value;
if(!(sline >> value))
{
throw invalid_argument("invalid data format");
}switch(pointElement)
{
case 'X':   data.x = value; break;
case 'Y':   data.y = value; break;
case 'Z':   data.z = value; break;
default:
// error in data format
throw invalid_argument("invalid data format");
}
}
else
{
// error in data format
throw invalid_argument("invalid data format");
}
}

// Do something with the values in data
cout
<< "point[x=" << data.x
<< ", y=" << data.y
<< ", z=" << data.z
<< "]" << endl;
}
}
file.close();

return 0;
}

При запуске против «myfile.txt» он производит следующий вывод

точка [x = 2, y = 5, z = 6] точка [x = 4, y = 2, z = 0] точка [x = 4, y = 1, z = 2]

2

Другие решения

Может быть, вы захотите использовать ifstream / stringstreams, чтобы сделать вашу жизнь проще, хотя это не самый быстрый способ …

int pt[3];
string line,dummy;

... //to where you were
if (line[0]=='P')
{
num++;
for (int i =0; i<3; ++i)
{
getline(file,line);
stringstream ss(line);
ss>>dummy;
ss>>pt[i];
std::cout<<"got "<<pt[i]<<std::endl;
}
}

Вы также должны включить Sstream и Fstream

1

внутри цикла while вы всегда можете добавить что-то вроде этого:

if(line.size() > 3){
if(line[0] == '<' && line[1] == 'X' && line[2] == '>'){
//enter code here
} else if(line[0] == '<' && line[1] == 'Y' && line[2] == '>'){
//enter code here
} else if(line[0] == '<' && line[1] == 'Z' && line[2] == '>'){
//enter code here
}
}

затем сделать что-то вроде подстроки строки и удалить < X> / < Y> / < Z> и никаких пробелов или спецсимволов.

после этого вы можете привести оставшуюся строку к тому, что вам нужно

редактировать:
немного лучший способ

  if(line.find("< X> ") != string::npos){
//enter code here
} else if(line.find("< Y> ") != string::npos){
//enter code here
} else if(line.find("< Z> ") != string::npos){
//enter code here
}
1

Это очень похоже на ответ С. Гримминка.

#include <iostream>
#include <string>
using namespace std;
int main()
{
const char FileName[] = "myfile.txt";

int num = 0;
int x = 0;
int y = 0;
int z = 0;
string line;
std::stringstream str_parse(line);
ifstream file;
file.open (FileName);

while(file.eof() == false)
{
getline(file, line);

if (line[0]=='P')
num++;
if( line.size() > 3 )
{
if( (line[0] == '<') && (line[1] == 'X') && (line[2] == '>'))
{
line = line.substr(3,line.size());
str_parse>>x; // Gets the x-coordinate
}
else if((line[0] == '<') && (line[1] == 'Y') && (line[2] == '>'))
{
line = line.substr(3,line.size());
str_parse>>y;  // Gets the y-coordinate
}
else if((line[0] == '<') && (line[1] == 'Z') && (line[2] == '>'))
{
line = line.substr(3,line.size());
str_parse>>z;  // Gets the z-coordinate
}
}
}
file.close();

return 0;
}

Это первый раз, когда я использую stringstream, Так что я могу ошибаться. Не стесняйтесь поправлять меня. 🙂

0

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

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

using namespace std;

struct Point {
Point() {}
Point(int x_, int y_, int z_) : x(x_), y(y_), z(z_) {}

int x, y, z;
};

istream& operator>>(istream& is, Point& p) {
is >> ws;

if (is.peek() != 'P') {
is.setstate(ios::failbit);
return is;
}

string pointStr;
is >> pointStr;
if (pointStr != "Point") {
is.setstate(ios::failbit);
return is;
}

int pointIdx;
is >> pointIdx;

string coordStr;
int x, y, z;

is >> coordStr;
if (coordStr != "<X>") {
is.setstate(ios::failbit);
return is;
}
is >> x;

is >> coordStr;
if (coordStr != "<Y>") {
is.setstate(ios::failbit);
return is;
}
is >> y;

is >> coordStr;
if (coordStr != "<Z>") {
is.setstate(ios::failbit);
return is;
}
is >> z;

p = Point(x, y, z);

return is;
}

int main() {
ifstream fileStream("data.txt");

string diamStr;
fileStream >> diamStr;
if (diamStr != "Diam")
throw istream::failure("Badly formatted file");

string dStr;
fileStream >> dStr;
if (dStr != "<D>")
throw istream::failure("Badly formatted file");
double diam;
fileStream >> diam;

string time, date;
fileStream >> time >> date;

istream_iterator<Point> pointIt(fileStream);
vector<Point> points;
copy(pointIt, istream_iterator<Point>(), back_inserter(points));

cout << points.size() << " points:\n";
for_each(begin(points), end(points), [](const Point& p) {
cout << "(" << p.x << ", " << p.y << ", " << p.z << ")\n";
});
}
0

Вы можете создать массив координат следующим образом: int coords[num*3];

Затем сохраните номера координат в их соответствующей позиции, используя функцию модуля и находя позицию с pos mod 3 = 0 для x-координат, pos mod 3 = 1 для y-координат и pos mod 3 = 2 для z-координат.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector