» »

[C++][Naloga] Tekstovne datoteke, realna števila

[C++][Naloga] Tekstovne datoteke, realna števila

wat56 ::

Hja tukaj mam spet problem :)

Napišite program, katerega vhod je tekstovna datoteka VHOD, izhod pa tekstovna datoteka IZHOD, na kateri so shranjeni vsi tisti stavki, ki vsebujejo neko realno število (uporabljena je C++ sintaksa realnega števila). Program naj pove koliko procentov stavkov ne vsebuje realnega števila.

Ali obstaja kaksna funkcija, za realna stevila? Ali moram sam napisat.
Kako naj sploh to napisem.. ;(

Vesoljc ::

jah ponavadi so realna stevila zapisana z decimalno piko/vejico. torj isces nekaj takega XX.XXXXX kje so X stevke. poglej si recimo sscanf, ali kaj podobnega...
Abnormal behavior of abnormal brain makes me normal...

wat56 ::

realna stevila so ponavadi v taksni obliki ja.
vendar moram zajeti vse mozne oblike npr: 5e-2 .05e2 itd

delam v okoju windows, zato me zanima kako se imenuje ukaz fscanf (ki se kolikor vem uporablja v UNIX okolju) ?

a je fscanf=getline ?

Vesoljc ::

cisto isto ni, zna pa biti podobno :)
char polje[255];
fscanf(file, "%s", polje );


zgornji kos je skorajda enak getlinu.
lahko pa naredis tudi tole (vsaj mislim :p):
// vsebina tekst fileta:
// velikost=3.601;dolzina=55.667
float vel, dol;
char polje[255];
fscanf(file, "%s=%f;%s=%f", polje, &vel, polje, &dol );



tukaj
Abnormal behavior of abnormal brain makes me normal...

wat56 ::

Hm

kako pa naj spravim to kar si ti napisal tu noter?

tole sicer ne dela je pa nazorni prikazano kaj bi rad anredi l:)

while (!itxtfile.eof())	
    {
          itxtfile.get (znak);	
          if (znak==%f)
          otxtfile.put (znak);
         
    }

snow ::

Problem je v tem: if (znak==%f) (napaka v preverjanju %f ni spremenljivka, % ne more biti prvi znak)

Ti hočeš preveriti če si dobil cifro - get ti vrne en znak.

if(znak>='0' && znak<='9')

ti preveri če je tvoj dobljen znak res znak.
Random mutation plus nonrandom cumulative natural selection - Richard Dawkins

Zgodovina sprememb…

  • spremenilo: snow ()

wat56 ::

ali pa isdigit(znak)

nalogo sem si tako zamislil
prebere besedo
besedko nekam shrani kot string (kot string zato, ker tole 5e-2 .05e2 je v resnici realno stevilo, vendar ce ga kot besedo preberes iz datoteke potem je se vedno string)
potem pretvori oz preveri, ce lahko string pretvori v float. (ali je to mozno?) (ce je mozno in ce mi kdo zna to razlozit, go for it prosim :) )
ce je beseda tipa float pa na izhodno datoteko zapise stavek, kjer se nahaja ta beseda.

Vesoljc ::

*scanf skupina bojda prebavi tudi stevila v eksponentne zapisu torej, 6e10 ipd...
probaj
Abnormal behavior of abnormal brain makes me normal...

wat56 ::

A se da komu tole prevest v c++ in za uporabo v windowsih :) ?

main(int argc, char *argv[])
{
   FILE *fp;
   float stevilo;
   double vsota = 0

	if(argc < 2)
	{
	   printf("Uporaba: %s ime_datoteke\n", argv[0]);
	   exit(2);
	}
	
	if( (fp=fopen(argv[1],"r")) == NULL)
	{
	   printf("Napaka: odpiranje %s za branje\n", argv[1]);
	   exit(1);
	}

	while (fscanf(fp, "%g", &stevilo) > 0 )
	{
	   printf("prebrano stevilo: %g\n", stevilo);
	   vsota += stevilo;
	}
	fclose(fp)
	printf("Vsota stevil iz %s je %g\n", argv[1], vsota);
	exit(0);
}

64202 ::

Saj to bo čisto lepo delalo pod winsi...
I am NaN, I am a free man!

wat56 ::

Nisem niti poizskusil se, bedak js :)

v glavnem tole sem spravil skup:

#include <iostream>
using namespace std;

int main ()
{
  char str [80];
  float stevilo;
  FILE * datoteka;
  

  datoteka = fopen("VHOD.txt","r+");
  while (fscanf(datoteka, "%f", &stevilo) > 0 )
	{
	   cout << "prebrano stevilo:" <<  stevilo << endl;
	 
	}
  fclose (datoteka);
  return 0;
}


vendar pa program deluje samo takrat, kadar so v datoteki samo števila.
Kako ga naj popravim ?

edit****
poskusal sem popravit, vendar se program ob zagonu sesuje :D
ima kdo mogoce kaksen namig, kaj naj spremenim.

int main ()
{
	char vrstica [80];
    float stevilo;
    FILE * datoteka;
  

	datoteka = fopen("VHOD.txt","r+");
	while (fgets(vrstica,80,datoteka) !=NULL)
	{
		 if( (fscanf(datoteka, "%f", &stevilo) != NULL ))
		 {
	 //  cout << "prebrano stevilo:" <<  stevilo << endl;
        	 cout << vrstica;
	 
		 }
	}
  fclose (datoteka);
  cout << endl;
  return 0;
}

Zgodovina sprememb…

  • spremenilo: wat56 ()

Gundolf ::

zakaj ne uporabiš raje C++ streamov namesto bolj nevarnih Cjevskih funkcij? Postopek si pa jaz predstavljam nekako takole:
odpreš fajl v ifstream
fajl bereš po vrsticah (getline(ifstream, string))
vsako vrstico daš v istringstream
v zanki, ki teče od prvega do predzadnjega znaka vrstice, preizkusiš:
prebrati en double z operatorjem >>
če ne uspe, iz vrstice z igonre(1) odstraniš en znak in nadaljuješ zanko
če uspe greš na naslednjo vrstico

To bo seveda našlo vsa števila, ne le tista v realnem zapisu. Za težji del naloge bi bilo najbolje ali napisati svojo funkcijo, ki bi znala prebrati le števila v realnem zapisu (se pravi če bi naletela na int ga ne bi znala prebrat) ali pa malo popravljeni zgornji postopek ponoviti še z iskanjem celih števil in potem pogledati razlliko.

Zdaj ti bom pa še kar direkt povedal, da ti očitno kar dobro sfalijo same osnove C++, zato bi te napotil na kakšen lep tutorial (recimo cplus.about.com) in pa na kakšno stran z C++ referencami (recimo cppreference).

wat56 ::

Karkoli nardim mi ne gre.
Prosim pomagajte mi.

Lahko predpostavim, da so stavki vsak v svoji vrstici in da so realna stevila podaana z decimalno piko.

Vendar ne znam naredit.
Morem pa oddat do ponedeljka.

while (!temp_datoteka.eof())
		{
		    itxtfile.getline(vrstica, 200);
		   len=strlen(vrstica);
    	           strcpy(vrstica,temp);
		  for (int i=0; i<len; i++)
//tukaj pa ne najdem funkcije, ki bi vrnila znak iz i-te pozicije.

tu sem poskusal na taksen nacin, vendar se mi je ustavlo

Drugace pa se naredil tudi tako

hile (!itxtfile.eof())	
    {
		itxtfile.get (znak);
		if (isdigit(znak))  //tu zaenkrat preverja samo stevila, kasneje bi dodal se kaksen 
                                              //if stavek
		{
			itxtfile.getline(vrstica,500, '\n');
		}
			 otxtfile << vrstica << endl;
	}



Zraven te naloge sem pa res popolnoma zgubljen..
Hvala za pomoc.

Zgodovina sprememb…

  • spremenilo: wat56 ()

kihc ::

Zadeva spodaj prebere zadevo in ti jo izpiše v konzolo. Vse tole in še več seveda najdeš na googlu.

#include <iostream>
#include <fstream>

int main()
{
    using namespace std;
    
    float stevilo;
    char file[] = {"vhod.txt"};    
    
    ifstream examplefile (file);
    if(!examplefile.is_open())
    {
        cout << "Napaka pri odpiranju fileta";
        return 0;
    }
    while(!examplefile.eof()) //dokler ne pride do konca
    {	
       examplefile >> stevilo; //prebere stevilo 
        cout << stevilo; //naredis z njim kar hoces 
    }
    
    cin.ignore().get();
    return 0;
}    

x

wat56 ::


ofstream izhodna("krneki.txt");     
    while (!itxtfile.eof())	
    {
	
		itxtfile.getline(vrstica,100, '\n');
		istringstream temp(vrstica);
		len=strlen(vrstica);	 
		for (int i=0; i<len; i++)
		{



kako naj se zdaj sprehodim cez tole vrstico, ki jo imam v temp?

nekako takole ane: x=strncpy(vrstica,i,1) ?
da bom pol lahko preveru ce je x stevilka..
pred sabo imam napisanih kar doti funkcij za delo s stringi, pa ne najdem prave..

Gundolf ::

Dve stvari, branje v char[] je še vedno nevarno in pa dostopanje do i-tega znaka stringa ali char[] se naredi takole:
string vrstica;
getline(itxtfile, vrstica);
for (int i = 0; i < vrstica.size(); ++i) {
   if (vrstica[i] == ...) {
      ...
   }
}

Gundolf ::

No ker se danes počutim še posebej ustrežljivega (očitno) dam tule celotem programček (celo z nekaj komentarji 8-O):
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

struct LineVar {
	string line;
	
	// vrne -1, če ne najde števila v double notaciji, sicer pa pozicijo 
	// tega števila v vrstici
	int seekReal() const {
		float temp;
		istringstream inStream(line);
		
		for (int i = 1; i < line.size(); ++i) {
			// postavi pozicijo za branje v streamu na i-1
			inStream.seekg(i-1);
			int temp;
			inStream >> temp;
			// je branje inta spodletelo?
			if (inStream.fail()) {
				// ja -> počisti error flage streama (drugače bodo vsa 
				// nadalnja branja spodletela)
				inStream.clear();
			} else {
				// ne -> poskusi prebrati še double (iz iste pozicije)
				int endOfIntString = inStream.tellg();
				inStream.seekg(i-1);
				double tempd;
				inStream >> tempd;
				// če je branje uspelo (torej iz neke pozicije se 
				// da prebrati in int in double), ter je
				// dolžina stringa, ki predstavlja int drugačna 
				// dolžini stringa ki predstavlja double,
				// potem smo našli število, ki je v double notaciji.
				if (!inStream.fail() && ((int)inStream.tellg() != endOfIntString))
					return i;
			}
		}
		
		return -1;
	}

};

// overloadan operator, da lahko rečemo istream >> LineVar
istream& operator>> (istream& in, LineVar& v) {
	getline(in, v.line);
	return in;
}

int main(int argc, char** argv) {
	if (argc < 2) {
		cout << "please specify a file\n";
	} else {
		cout << "parsing " << argv[1] << "\n\n";
		try {
			ifstream file(argv[1]);
			LineVar lineVar;
			
			while (file >> lineVar) {
				if (lineVar.seekReal() >= 0) {
					cout << lineVar.line << "\n";
				}
			}
			
			if (file.fail() && !file.eof()) {
				cout << "\nreading failed, bailing out\n";
			}
		} catch (...) {
			cout << "\noops, an exception\n";
		}
	}
	return 0;
}

No ja morda so pa motivi za podajanje celotne kode bolj grdi in sicer, da se čimmanj folka nauči c++ in s tem meni hodi v zelje >:D
krneker, svetujem ti, da ven pobereš le ideje, sicer je pa čisto tvoj problem kaj narediš in kaj ne narediš s to kodo.

Aja koda je seveda obsežno testirana in sigurno nima hroščev. Nobenih.

P.S. Opažam (in se ne sekiram) veliko nedoslednost z vejicami v komentarjih. No ja, podarjeni kodi se ne gleda v komentarje.

Zgodovina sprememb…

  • spremenil: Gundolf ()

wat56 ::

Podarjeni kodi se ne gleda v komentarje :D lol

Hvala lepa za pomoc! Oz za resitev :) Vsekakor ne bom kopiral, bom pa potegnil ven kaksno idejo :)
Se enkrat hvala vsem za pomoc.

wat56 ::

:)
js pol kode sploh ne razumem :)

Gundolf ::

katere polovice ne razumeš? >:D

P.S. Če recimo ne veš kaj dela katera funkcija (recimo seekg, tellg) pogledaš v help/na internet. Če ne veš kaj je operator>> si pogledaš kaj je to operator overloading. Če ne veš kaj je try {...} catch (...) {...} si poglej exception handling. Če pa kaj drugega pa kar direkt vprašaj.

Zgodovina sprememb…

  • spremenil: Gundolf ()

wat56 ::

hja :)
sredinsko polovico ne razumem :)

while (!itxtfile.eof())	
    {
	
		itxtfile.getline(vrstica,100, '\n');
		vrstice++;
		len=strlen(vrstica);
        	 
		for (int i=0; i<len; i++)
		{
			 if ((isdigit(vrstica[i]))&& ((vrstica[i+1])=(','))&&(isdigit(vrstica[i+2])))
			 
			 {
				izhodna << vrstica << endl;
				vrstica_s_stevilom++;
				break;
             }

		}
     
	}


tukaj me nekaj zanima, zakaj mi na izhodno ne zapise vrstice 'as it is', ampak jo nekako cudno modificira..
ne stekam zakaj se to zgodi, sej sem pa lepo napisal da zapisi vrstico gor, ce je pogoj izpolnjen.
zakaj modificira..


tole se zgdi :
tukaj in tam 15,8777 odstotkov //na vhodni datoteki
tukaj in tam 1,,8,77 odstotkov //na izhodni pa tale zmazek


oz kako bi tole kodo visje naredil z .get namesto z getline?

Zgodovina sprememb…

  • spremenilo: wat56 ()

wat56 ::

pa se nekaj.
gundolf zakaj v tistem programu, ki si ga napisal isces stevila tipa double? (a se da kar spremenit v float? )



p.s
Naj nekdo preizkusi ta program. Se vedno ne razumem, zakaj na izhodno datoteko IZHOD.txt ne zapise vrstice, ki jo dobi iz poljubne vhodne .txt datoteke.
txt datoteko z besedilom instevili imejte v istem folderju, iz katerega izvajate program.
Stavki so podani v vrsticah.
Stevila pa so podana z decimalno vejico.
Kadar je podano stevilo recimo 4,556 potem vrstico izpise pravilno, kadar pa je 556,44 recimo, pa je ne izpise prav.
Sumim pogoj, vendar po kmecki logiki do tega nebi smelo prit, ker itak ,ko izpolni pogoj pac naj zapise gor vrstico.
What to do?

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <sstream>
using namespace std;

int main ()
{
    ifstream itxtfile;
    ofstream otxtfile;

    char dat1[56];	   
    char vrstica[1000];
    char znak;
    char temp[100];
    int len;
    float stevilo;
    float x;
    int vrstice=0;
    int vrstica_s_stevilom=0;
    int stavki=0;
    
    cout << "Vhodna datoteka: ";
    cin >> dat1;
    cout << endl;
    itxtfile.open (dat1);   // odpremo vhodno datoteko
    
    if (!itxtfile)	// ce je prislo do napake pri odpiranju datoteke
    {
       cout << endl << "Napaka pri odpiranju datoteke: " << dat1 << endl;
       cout << endl << "Program bo koncan" << endl;
       exit (1);;		// se program zakljuci
    }

    ofstream izhodna("IZHODNA.txt");     
    while (!itxtfile.eof())	
    {
                itxtfile.getline(vrstica,1000, '\n');
		vrstice++;
		len=strlen(vrstica);
        	 
		for (int i=0; i<len; i++)
		{
			 if ((isdigit(vrstica[i])) && ((vrstica[i+1])=(',')) && (isdigit(vrstica[i+2])))			 
			 {                      
				izhodna << vrstica << endl;
				vrstica_s_stevilom++;				
			        break;
                           }
                }
     
     }
	
    stavki=vrstice-vrstica_s_stevilom;
    x=((100*stavki)/vrstice);
    cout << "Realnega stevila ne vsebuje " << x <<" % stavkov";
    system("pause");
    return 0;
}

wat56 ::

ok zadeva mi lavfa.
Deluje za vsa realna stevila podana z decimalno vejico.
Ce kdo zeli kodo naj pove.

Najlepsa hvala vsem za pomoc!

Gundolf ::

Ja double je pač flaot z večjo natančnostjo. Tekstovni zapis obeh je enak.

Takole komentar še:
itxtfile.getline(vrstica,100, '\n'); // vrstica je char* oz. char[100]
se spremeni v
getline(itxtfile, vrstica) // vrstica je string
kar je veliko boljše (deluje tudi na vrsticah daljših od 100). Ostala koda ostane ista (npr: f ((isdigit(vrstica[i])) && ((vrstica[i+1])=(',')) && (isdigit(vrstica[i+2]))) ). Le še strlen(vrstica) se epremeni v vrstica.size().

Ena prav v nebo vpijoča napaka pa je ta, da greš v zanki z i-jem čez vse znake, in v if-u znotraj zanke pa potem pregleduješ i-ti, i+1-i in i+2-i znak (se pravi lahko bereš že 2 znaka zven vrstice).

wat56 ::

lol
zamesal sem double z long :)

tudi ce bere izven zanke in ce pogoj ni izpolnjen stavka ne bo zapisal na datoteko.Tako, da ni neke panike.

Zgodovina sprememb…

  • spremenilo: wat56 ()

Gundolf ::

> tudi ce bere izven zanke in ce pogoj ni izpolnjen stavka ne bo zapisal na datoteko.Tako, da ni neke panike.

Absolutno je panika. Ne gre se za to, ali program deluje pravilno ali ne (in sploh ni nujno da deluje pravilno v tem primeru, da bere izven tabele). Ne bere izven zanke ampak izven pomnilnika, ki je določen za to.


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

[c] Enaki datoteki

Oddelek: Programiranje
7972 (832) Spura
»

[C] Branje iz datoteke

Oddelek: Programiranje
101677 (1508) BigWhale
»

[C++] Delo s *.txt datotekami

Oddelek: Programiranje
191979 (1455) Tr0n
»

branje iz datoteke c/c++

Oddelek: Programiranje
101394 (1263) Vesoljc
»

[C++][Naloga_polja]MIN in MAX polja, izpis za x.100 stevil

Oddelek: Programiranje
222856 (2667) snow

Več podobnih tem