|
[ adnanK @ 14.07.2008. 11:06 ] @
| Dakle, imam fajle iz kojih trebam pročitati podatke. U njima su zapisane koordinate tačaka, a imaju i header koji me ne interesuje. Dva primjera:
1)
[Version]
VersionLevel=4
[Konturs]
KonturCnt=1
[Kontur0]
PtCnt=450
Pt0=672.000 2661.000
Pt1=725.000 2651.000
Pt2=775.000 2636.000
Pt3=811.000 2632.000
Pt4=817.000 2624.000
2)
[Version]
VersionLevel=4
[Konturs]
KonturCnt=1
[Kontur0]
PtCnt=494
Pt0=505.000 2716.000
Pt1=554.000 2681.000
Pt2=589.000 2664.000
Pt3=648.000 2617.000
Pt4=648.000 2557.000
Dakle, ja sad trebam pročitati prvo koji je broj poslije "PtCnt=" i to smjestiti u varijablu "count" tipa integer, a zatim čitati koordinate jedne po jedne tačke (označene sa "Pt*=") i smještati ih u varijable "X" i "Y" tipa double (u svakom prolazu vrijednost ovih varijabli će se mijenjati). Kako ovo da uradim? Hvala |
[ X Files @ 14.07.2008. 11:35 ] @
Fajl koji si prikazao i u kome se cuvaju podaci o koordinatama i broju tih koordinata - je klasicana INI datoteka.
Borland C++ Builder raspolaze vrlo upotrebljivom klasom TIniFile za baratanje INI datotekama i ima sve potrebne metode za iscitavanje vrednosti.
Pokusacu da ti dam i neki primer, samo moras prethodno reci da li ces koristiti TIniFile, odnosno moguce resenje u okvirima VCL biblioteke klasa (u prethodnom postu si koristio neka genericka resenja, pa nisam siguran)?
[ X Files @ 14.07.2008. 11:56 ] @
Pod pretpostavkom da se INI fajl nalazi gde i EXE i da se zove config.ini
// NETESTIRANO
Code:
// ...
#include "IniFiles.hpp"
#include "StrUtils.hpp"
// ...
int count;
double x,y;
// ...
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TIniFile *pIniFile = NULL;
try
{
AnsiString Fajl = ExtractFilePath( ParamStr(0) ) + "config.ini";
if ( FileExists( Fajl ) )
{
pIniFile = new TIniFile( Fajl );
count = pIniFile->ReadInteger("Kontur0", "PtCnt", 0 );
for ( int i=0; i<count; i++ )
{
AnsiString Temp = pIniFile->ReadString( "Kontur0", AnsiString( "Pt" + IntToStr(i) ), "" );
if ( Temp != "" )
{
int Blanko = AnsiPos( " ", Temp );
if ( Blanko != 0 )
{
AnsiString X = LeftStr( Temp, Blanko-1 );
AnsiString Y = RightStr( Temp, Temp.Length()-Blanko);
try
{
x = StrToFloat( X );
y = StrToFloat( Y );
// *************
// OVDE TVOJ KOD
// *************
}
catch ( const Exception &e )
{
ShowMessage( e.Message );
}
}
}
}
}
else
{
ShowMessage( "Datoteka: " + Fajl + " ne postoji!");
}
}
catch ( const Exception &e )
{
ShowMessage( e.Message );
}
if ( pIniFile )
delete pIniFile;
}
Inace, na osnovu INI fajla zakljucujem da moze da bude vise KONTUR sekcija. Taj slicaj obradjujes slicno kao i ovo sto je prikazano.
[ adnanK @ 14.07.2008. 13:58 ] @
Hvala ti sto si se potrudio, ali nazalost ne mogu koristiti compiler dependant biblioteke (stoga ni VCL), nazalost. Ja pokusavam nesto sa fscanf, ali mi bas i ne ide.
Code:
FILE *in;
in = fopen ("test.SAV","r");
if(in!=NULL)
{
int x, y;
int i=0;
char str [80]=" ";
while(strcmp(str,"Pt0")) // da preskocim header
{
fscanf (in, "%s", str);
fscanf (in, "%d", &i);
}
while(!feof(in))
{
fscanf (in, "%d", &x);
fscanf (in, "%d", &y);
/* ovdje sad koristim x i y */
}
Gledajuci duzinu tvog koda cini mi se da moj i ne moze raditi
Jos jedna stvar je da mi ne treba niti desetak linija na kraju fajle, pa pretpostavljam da uslov !feof(in) u drugoj while petlji nije dobar. Neki prijedlog i za ovo?
[ X Files @ 14.07.2008. 18:27 ] @
1. Da li u toj INI datoteci moze da se nadje vise KonturX sekcija, jer zamisljena struktura to dozvoljava.
Primer:
[Konturs]
KonturCnt=3
[Kontur0]
PtCnt=2
Pt0=505.000 2716.000
Pt1=554.000 2681.000
[Kontur1]
PtCnt=4
Pt0=505.000 2716.000
Pt1=554.000 2681.000
Pt2=589.000 2664.000
Pt3=648.000 2617.000
[Kontur2]
PtCnt=3
Pt0=505.000 2716.000
Pt1=554.000 2681.000
Pt2=589.000 2664.000
2. Da li smes da koristis STL biblioteku, ona nije comiler dependant? Vidim da si za pristup koristio ciste C funkcije pa zato pitam.
Parsovanje ovakve strukture nije tesko, samo da se znaju odgovori na gore postavljena pitanja. Ovde mozes pogledati kako da zapocnes citanje fajla red po red, sve to redom pakujes u vektor stingova, i kasnije biras sta ces sa redovima (brises, koristis i sl).
EDIT:
3. Da li stavke Pt0, Pt1 itd, mogu da se nadju u proizvoljnom (izmesanom) redosledu u INI fajlu, sto jeste moguce u klasicnoj INI strukturi ?
[Ovu poruku je menjao X Files dana 14.07.2008. u 20:18 GMT+1]
[ adnanK @ 15.07.2008. 10:56 ] @
1. Moze da se nadje vise kontura u fajli
2. Mogu koristiti STL
3. Mislim da su tacke uvijek poredane
Imam neko rjesenje, iako mi se ne svidja bas pretjerano:
Code:
FILE *in;
in = fopen (F,"r");
if(in!=NULL)
{
int i=0, u=0; // i - broj tacaka
char str [80]=" ";
/* Ovdje sam rucno postavio da mi se petlja vrti 35 puta jer znam da imam toliko kontura,
tako da nisam rijesio kako da ih automatski citam (nigdje u fajli nije naveden broj kontura).
Dobra stvar je sto konture uvijek pocinju oznakom PtCnt=# gdje je # broj tacaka koje se
nalaze u njoj, pa se to moze iskoristiti ali nisam siguran kako :( */
while(u!=35)
{
u++ ;
/* Trazim PtCnt */
while(strncmp(str,"PtCnt",5))
{
fgets (str, 80, in);
}
sscanf(str + 6, "%d", &i); // i - broj tacaka
/* citamo liniju po liniju kad smo vec dosli do Pt#=, izdvajamo koordinate */
for( int j = 0; j < i; j++)
{
int xf, yf;
fgets (str, 80, in);
string str_pravi(str);
sscanf(str + str_pravi.find("=",0) + 1 , "%d", &xf);
sscanf(str + str_pravi.find(" ",0) + 1, "%d", &yf);
// koristim xf i yf
}
}
fclose(in);
}
Problem sa ovim jeste ako se struktura fajle imalo promijeni, funkcija vise nece citati. Drugi problem je sto ne mogu ucitati sve konture.
[ X Files @ 15.07.2008. 12:04 ] @
Citat:
Problem sa ovim jeste ako se struktura fajle imalo promijeni, funkcija vise nece citati.
INI struktura ima precizno definisanu formu, upravo iz razloga da bi citanje i upisivanje iz razlicitih programa bilo 100% kompatibilno. Drugim recima, potrebno je promeniti algoritam koji si koristio, a pre svega razmisliti o interfejsu za koriscenje, tj o nekoj klasi koja bi imala metode slicne TIniFile klasa.
Eto na primer, prototip jedne metode (ili eventualno samo funkcije) bi mogao biti:
string ReadString( const string SEKCIJA, const string KLJUC, const string DEFAULT_VREDNOST );
Citat:
Drugi problem je sto ne mogu ucitati sve konture.
Dakle, i ovo treba predvideti... upravo zato sam i pominjao redizajn.
(Sad sam trenutno u guzvi, ako budem imao vremena pomoci cu ti da barem zapocnes)
[ idb @ 15.07.2008. 13:43 ] @
Mislim da ti treba nesto ovako:
1. Treba da iscitas vise izlomljenih linija cije su tacke (x0,y0), (x1,y1), (x2,y2), ..., (xi,yi), ...
- Tacku mozes da napravis kao klasu ili structuru (MyPoint)
- Izlomljenu liniju mozes da napravis kao klasu (MyPolyLine) koja ima svoj ID i niz tacaka (srd::vector)
2. Fajl citaj liniju po liniju
Napravi tokenizer f-ju (samostalno ili iskoristi http://www.rosettacode.org/wiki/Tokenizing_A_String ) kojom ces procitati tokene u liniji.
Kad naidjes na token "PtCnt" (iz naprimer linje "PtCnt=450") - ti kreiraj novu promenljuvu tipa <MyPolyLine> ciji je ID = atoi("450") (drugi token iz linije)
Citaj dalje linije i dobijas tokene npr: "Pt0", "672.000", "2661.000".
- Ako su prva dva znaka prvog tokena "Pt" dodaj novu kordinatu u vektor ...
Radio sam nesto slicno pa cu ti malo kasnije dostaviti prilagodjen kood.
idb
[ idb @ 15.07.2008. 14:27 ] @
Code: // file: nove_klase.h
#ifndef NOVE_KLASE_H_INCLUDED
#define NOVE_KLASE_H_INCLUDED
#include <vector>
#include <string>
// Pojednostavljene verzije klasa ....
class Point {
//private: // u cilju pojednostavljenja
public:
double x; // moses ih kasnije staviti u private
double y; // ako napravis inspector i mutator member functions
Point(const double& xx=0.0, const double& yy=0.0):x(xx), y(yy){}
Point(const Point& p);
~Point(){}
};
class PolyLine {
//private: // opet pojednostavljenje
public:
int id;
std::vector<Point> mPoint;
PolyLine(const int& i):id(i){}
~PolyLine();
void AddPoint(const double& x, const double& y);
};
// Default delimiteri su "=" i " "
int MyTokenizer(const std::string& str, std::vector<std::string>& tokens, const std::string& delims="= ");
#endif // NOVE_KLASE_H_INCLUDED
// end of file: nove_klase.h
Code: // file: nove_klase.cpp
#include <iostream>
#include "nove_klase.h"
Point::Point(const Point& p){
x = p.x;
y = p.y;
}
void PolyLine::AddPoint(const double& x, const double& y){
mPoint.push_back( Point(x,y) );
}
PolyLine::~PolyLine(){
if (!mPoint.empty()) mPoint.clear();
}
int MyTokenizer(const std::string& str, std::vector<std::string>& tokens, const std::string& delims) {
/*
modifikovana verzija orginala:
http://www.rosettacode.org/wiki/Tokenizing_A_String#C.2B.2B
*/
using namespace std;
string::size_type lastPos = str.find_first_not_of(delims, 0);
string::size_type pos = str.find_first_of(delims, lastPos);
size_t count(0);
while ( (string::npos != pos || string::npos != lastPos) && count<3 ) {
tokens[count] = str.substr(lastPos, pos - lastPos);
lastPos = str.find_first_not_of(delims, pos);
pos = str.find_first_of(delims, lastPos);
count++;
}
if ( tokens[0].compare("PtCnt") == 0 ) return 0; // pocetak nove PoluLine
else if (tokens[0].substr(0,2).compare("Pt")==0) return 1; // nova tacka u PoluLine
else return -1;
}
// end of file: nove_klase.cpp
Nacin uptrebe:
Code: // file: program.cpp
#include <iostream>
#include <fstream>
#include <vector>
#include "nove_klase.h"
using namespace std;
int main() {
int odgovor;
vector<PolyLine> mPolyLine;
vector<string> token(3,"");
string line, delims = "= ";
ifstream in_file ("test.txt");
if (in_file.is_open()) {
while (! in_file.eof() ) {
getline (in_file,line);
odgovor = MyTokenizer(line, token, delims);
if (odgovor==0)
mPolyLine.push_back( PolyLine( atoi(token[1].c_str()) ) );
else if (odgovor==1)
mPolyLine[mPolyLine.size()-1].AddPoint( atof(token[1].c_str()), atof(token[2].c_str()) );
// Ocisti tokene
for (size_t t=0;t<token.size(); t++) token[t].clear();
}
in_file.close();
}
// Sada kad imas Konture kao objekte - mozes sa njima raditi sta hoces!
for (size_t p=0; p<mPolyLine.size(); p++) {
cout << "ID Konture = " << mPolyLine[p].id << endl;
for (size_t t=0; t<mPolyLine[p].mPoint.size(); t++) {
cout << " (" << mPolyLine[p].mPoint[t].x << ", " << mPolyLine[p].mPoint[t].y << ")\n";
}
}
return 0;
}
// end of file: program.cpp
Test podaci (fajla "test.txt") - nije orginal, ali po tvojoj prici izgleda priblizno ovako: Code:
[Version]
VersionLevel=4
[Konturs]
KonturCnt=1
[Kontur0]
PtCnt=450
Pt0=672.000 2661.000
Pt1=725.000 2651.000
Pt2=775.000 2636.000
Pt3=811.000 2632.000
Pt4=817.000 2624.000
[Version]
VersionLevel=4
[Konturs]
KonturCnt=1
[Kontur0]
PtCnt=494
Pt0=505.000 2716.000
Pt1=554.000 2681.000
Pt2=589.000 2664.000
Pt3=648.000 2617.000
Pt4=648.000 2557.000
idb
[ adnanK @ 17.07.2008. 10:47 ] @
Extra. Hvala svima na odgovorima. Gotovo je sve rijeseno sa onim kodom sto sam poslao u proslom postu. Imam jos jedno pitanjce. Imam ovaj kod koji mi nadje liniju koja pocinje sa "PtCnt":
Code:
while(strncmp(str,"PtCnt",5))
{
fgets (str, 80, in);
}
sscanf(str + 6, "%d", &i);
Interesuje me mogu li se sad "vratiti" jednu liniju unazad jer mi treba i jedan podatak iz prethodne linije?
Copyright (C) 2001-2025 by www.elitesecurity.org. All rights reserved.
|