Načítání specifické proměnné z textového dokumentu – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu
Reklama
Reklama

Načítání specifické proměnné z textového dokumentu – C / C++ – Fórum – Programujte.comNačítání specifické proměnné z textového dokumentu – C / C++ – Fórum – Programujte.com

 

Hledá se programátor! Plat 1 800 € + bonusy (firma Boxmol.com)
ondrej39+1
Věrný člen
14. 11. 2014   #1
-
0
-

Ahoj,

mám dojem, že mě tady za chvilku budete nesnášet kvůli mým opakujícím se blbým dotazům. Vypracovávám úkol do školy, kde máme načítat vsupní informace z txt souboru. To samotné mi nečiní žádný problém, akorát mně přijde, že načítám zbytečně moc proměnných.

Takhle vypadá můj txt soubor se vstupními daty (ucet.txt):

101111 Honzik Novotny 12568.5632456 8 3 15400 2831.44
102345 Karel Pepik 103597.1402145 12 1 120000 16402.86
109865 Jindriska Dvorakova 5236.7054687 3 1 76000 70763.30

a takhle vypadá funkce součástí třídy Ucet, která s daty pracuje (ucet.cpp):

void Ucet::setCisloUctu(int cisloUctu)
{
	if (cisloUctu > 100001 && cisloUctu < 109999)
	{
		fstream test_id;

		string jmeno, prijmeni;
		int cislo_uctu, pocet_vkladu, pocet_vyberu;
		double balance, soucet_vkladu, soucet_vyberu;

		test_id.open("ucty.txt");

		while (test_id.good())
		{
			test_id >> cislo_uctu >> jmeno >> prijmeni >> balance >> pocet_vkladu >> pocet_vyberu >> soucet_vkladu >> soucet_vyberu;
			while (cisloUctu == cislo_uctu)
			{
				cout << "\nVámi zadané číslo účtu již existuje." << endl;
				cout << "Zadejte prosím jiné ID: ";
				cin >> cisloUctu;				
			}
		}
		this->cisloUctu = cisloUctu;
		test_id.close();
	}
	else
	{
		while (cisloUctu < 100001 || cisloUctu > 109999)
		{
			cout << "\nVámi zadané číslo účtu je špatné." << endl <<
				"Číslo účtu může být pouze mezi 100001 až 109999." << endl <<
				"Nové číslo účtu: ";
			cin >> cisloUctu;
		}
		fstream test_id;

		string jmeno, prijmeni;
		int cislo_uctu, pocet_vkladu, pocet_vyberu;
		double balance, soucet_vkladu, soucet_vyberu;

		test_id.open("ucty.txt");

		while (test_id.good())
		{
			test_id >> cislo_uctu >> jmeno >> prijmeni >> balance >> pocet_vkladu >> pocet_vyberu >> soucet_vkladu >> soucet_vyberu;
			while (cisloUctu == cislo_uctu)
			{
				cout << "\nVámi zadané číslo účtu již existuje." << endl;
				cout << "Zadejte prosím jiné ID: ";
				cin >> cisloUctu;				
			}
		}
		this->cisloUctu = cisloUctu;
		test_id.close();
	}
}

V rámci dané funkce potřebuji pouze otestovat, zda uživatel při tvorbě nového účtu nezadává ID, které již v systému (resp. txt souboru) existuje, pokud ano, systém ho vyzve, aby zadal ID jiné.

Můžete si však všimnout, že zbytečně načítám i další proměnné, které se v txt nacházejí (jmeno, prijmeni atd.).

Nevím, co konkrétně bych měl v googlu hledat, jak svůj problém pojmenovat, takže jsem nic nenašel, proto se obracím sem.

Poradili byste mi, jak funkci upravit, abych načetl pouze ID a zbytek (tedy konec řádku v txt) přeskočil?

Děkuju moc,

Ondra

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
Reklama
Reklama
Kenvelo+1
Super člen
16. 11. 2014   #2
-
0
-

#1 ondrej39
Načti z txt jen int cislo_uctu... jméno a další zbytečný proměnný nenačítej. ;)

Nahlásit jako SPAM
IP: 89.177.211.–
Díky bohu, že počítače vymysleli muži. Kdyby to byly ženy, tak binární soustavu reprezentují jedničky, nuly a "možná"
ondrej39+1
Věrný člen
18. 11. 2014   #3
-
0
-

#2 Kenvelo
A to nevadí, že budu načítat do int i stringy (jak tam mám jméno a příjmení majitele účtu), nebo stringy to načítání úplně přeskočí, protože string do int nelze přiřadit?

Nahlásit jako SPAM
IP: 195.113.207.–
Inject all the dependencies!
Kenvelo+1
Super člen
18. 11. 2014   #4
-
0
-

#3 ondrej39
Chceš načítat přece jen ID což je v tvém případě jestli sem dobře pochopil číslo účtu. Tak načteš čistě jen číslo účtu nebo sem tě spatně pochopil... Pokud si to myslel tak, že chceš načíst ID a pod tím id budou proměnné jako jména atd atd tak samozřejmě musíš načítat i ostatní ale spíš doporučuji udělat to tak že každé id bude mít svůj txt "číslo účtu" bude txt pro daného člověka

Nahlásit jako SPAM
IP: 89.177.211.–
Díky bohu, že počítače vymysleli muži. Kdyby to byly ženy, tak binární soustavu reprezentují jedničky, nuly a "možná"
Kenvelo+1
Super člen
18. 11. 2014   #5
-
0
-

#4 Kenvelo
Jinak pri načítání zpět do txt načítáš string do string respektive jmeno nacitas do string jmeno, atd atd pak si to samozřejmě můžeš převést jinam. 

Nahlásit jako SPAM
IP: 89.177.211.–
Díky bohu, že počítače vymysleli muži. Kdyby to byly ženy, tak binární soustavu reprezentují jedničky, nuly a "možná"
ondrej39+1
Věrný člen
21. 11. 2014   #6
-
0
-

#5 Kenvelo
Omlouvám se za opožděnou reakci. Zkoušel jsem funkci upravit, aby se načítalo pouze int cislo_uctu, ale když to tak udělám, tak mi program vezme i ID účtu, které již existuje. Nevím, kde je chyba, ale asi se na to vyprdnu. Kód funkční je, to do školy stačí, když tak se na to zeptám přímo profesora v hodině.

Každopádně děkuji za ochotu.

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
ingiraxo+15
Grafoman
21. 11. 2014   #7
-
0
-

#1 ondrej39
proč otevířáš a čteš soubor na setteru jen pro kontrolu, jestli existuje nějaký ID účtu??

Na tvém místě bych udělal následující... udělal bych si strukturu a následne její líst, kam bych předem načetl všechna data ze souboru a na tom settru bych jen kontroloval, jestli to id existuje v listu uctu a pokud to ma i zapisovat, tak potom dalsi metodu pro zapis (kde se zapise primo objekt Ucet)

struct Ucet {
public:
   int id;
   string jmeno;
   string prijmeni;
   // dalsi dle souboru...
};

class UcetniSystem {
public:
   void nactiUcty(string  nazevSouboru) { /* nacteni souboru do 'ucty' */ }
   // dalsi...

private:
   vector<Ucet *> ucty;
   // dalsi...
};
Nahlásit jako SPAM
IP: 213.168.183.–
Moje aplikace: http://ophite.cz
Tutoriály na: C#
ondrej39+1
Věrný člen
21. 11. 2014   #8
-
0
-

#7 ingiraxo
Moc nerozumím tomu, jak to myslíš. 1) Nejsem úplně zkušený programátor, 2) s vektory jsem ještě nikdy nepracoval 3) vůbec mi aktuálně ani nedochází, jak by například funkce nactiUcty mohla vypadat :D.

EDIT: Aktuálně to mám řešené vše přes jednu třídu, což není ideální, to chápu, ale nejsem v programování tak daleko, abych byl sto pochopit, jak to udělat nějak jinak.

Třídu mám takhle:

#pragma once;
#include <string>
using namespace std;

class Ucet {
private:
	string jmeno;
	string prijmeni;
	int cisloUctu;
	const int max_vklad = 100000;
	const int max_vyber = 5000;
	int pocetVkladu;
	int pocetVyberu;
	double zustatek;
	double soucetPrich;
	double soucetOdch;

public:
	Ucet();
	~Ucet();
	void setJmeno(string jmeno, string prijmeni);
	const string getJmeno() const;
	const string getPrijmeni() const;
	void setCisloUctu(int cisloUctu);
	const int getCisloUctu();
	const void getPocetVkladu();
	const void getPocetVyberu();
	const double getZustatek();
	const double getSoucetPrich();
	const double getSoucetOdcho();
	void vlozPenize(double zustatek);
	void vyberPenize(double zustatek);
	bool jeVIntervalu(int cisloUctu);

};
Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
ingiraxo+15
Grafoman
21. 11. 2014   #9
-
0
-

#8 ondrej39
ok.. takto nějak myslim 

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

using namespace std;

struct Ucet
{
public:
    int cislo;
    string jmeno;
    string prijmeni;
    int pocetVkladu;
    int pocetVyberu;
    double balance;
    double soucetVkladu;
    double soucetVyberu;
};

class SpravaUctu
{
public:
    void nactiUcty(string ucetniSoubor)
    {
        fstream f(ucetniSoubor);
        while (f.good()) {
            Ucet* ucet = new Ucet();
            f >> ucet->cislo;
            f >> ucet->jmeno;
            f >> ucet->prijmeni;
            f >> ucet->balance;
            f >> ucet->pocetVkladu;
            f >> ucet->pocetVyberu;
            f >> ucet->soucetVkladu;
            f >> ucet->soucetVyberu;
            ucty.push_back(ucet);
        }
    }

    Ucet* ziskejUcet(int cisloUctu)
    {
        vector<Ucet *>::const_iterator it = ucty.begin();
        for (; it != ucty.end(); it++) {
            if ((*it)->cislo == cisloUctu) {
                return *it;
            }
        }
        return NULL;
    }

private:
    vector<Ucet *> ucty;
};

class Uzivatel
{
public:
    void nastavUcet(SpravaUctu su, int cisloUctu)
    {
        Ucet* ucet = su.ziskejUcet(cisloUctu);

        if (ucet) {
            this->ucet = ucet;
            cout << "Ucet pro " << ucet->jmeno << " " << ucet->prijmeni << " byl nastaven\n";
        } else {
            cout << "Ucet s cislem " << cisloUctu << " neexistuje!\n";
        }
    }

private:
    Ucet* ucet;
};

int main()
{
    SpravaUctu su;
    su.nactiUcty("ucty.txt");

    Uzivatel u;
    u.nastavUcet(su, 102345);

    cin.get();
    return EXIT_SUCCESS;
}


ale rozhodně otevírat soubor při každým dotazu na nastavení účtu je pitomost.. teď to výkon moc nezhorší, ale kdyby si měl třeba tisíce účtů, tak to rozhodně už nesmíš dělat tak jak teď

co se týče vectoru, tak to je klasický dynamický pole (dynamický proto, protože neznáš předem počet účtů)

Nahlásit jako SPAM
IP: 213.168.183.–
Moje aplikace: http://ophite.cz
Tutoriály na: C#
ondrej39+1
Věrný člen
21. 11. 2014   #10
-
0
-

#9 ingiraxo
Jirko, děkuju moc za kód, použiji ho pro nastudování lepších technik (určitě se mi to bude do budoucna hodit), ale implementaci nechám zatím tak, jak ji mám. Je to školní projekt, tam po nás skoro nic nechcou, rozhodně vím, že to, co jsi napsal, bych já sám nevymyslel, proto je blbost, abych to použil.

Tvou připomínku ohledně nároku na výkon chápu, rovněž chápu, že pro můj projekt mi to může být jedno (ten prográmek bude tak malinký, že se to na výkonu opravdu nepodepíše), ale i mě zarazilo načítání všech proměnných, proto jsem toto vlákno zakládat (nicméně problém se mi stejně vyřešit nepovedlo).

Jak jsem psal, asi to proberu v pondělí ve škole přímo s profesorem, uvidím, kam mě navede on. Bohužel na škole je dost kluků, kteří ani neví, že je potřeba si nadeklarovat proměnnou, abys ji mohl použít, takže se tam spíš programuje smyslem: "Hlavně ať to jede, ani nemusí být ověřený všechny podmínky, stačí, když to spustíš," namísto toho, aby se tam programovalo správně - nicméně chápu, že aby se člověk naučil programovat dobře, tak se o daný jazyk prostě musí zajímat a nespoléhat na to, co ho naučí ve škole.

Ještě jednou děkuji.

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
ingiraxo+15
Grafoman
21. 11. 2014   #11
-
0
-

#10 ondrej39
tak tam aspoň použij nějakou metodu, která bude číst a detekovat existenci čísla učtu ze souboru, nemůžu se koukat jak to tam máš v settru "zajímavě" řešený, to mi úplně trhá oči  :) 

bool jeUcetUplatny(string ucetniSoubor, int cisloUctu)
{
    fstream f(ucetniSoubor);
    bool existuje = false;
    string radek;

    while (f.good()) {
        getline(f, radek);
        if (radek.length() == 0) break;
        int ucet = atoi(radek.substr(0, radek.find(' ')).c_str());
        if (ucet == cisloUctu) {
            existuje = true;
            break;
        }
    }
    f.close();
    return existuje;
}

PS: konstanty dělej jako definice

Nahlásit jako SPAM
IP: 213.168.183.–
Moje aplikace: http://ophite.cz
Tutoriály na: C#
ondrej39+1
Věrný člen
22. 11. 2014   #12
-
0
-

#11 ingiraxo
Myslel jsi to tak, že mám poté v setteru pro ověření použít metodu jeUcetUPlatny, chápu to správně? Nebo bych měl metodu jeUcetUPlatny použít normálně v mainu?

+ jak mám dělat constanty jako definice? Normálně přes #define MAX_VYBER 5000; a #define MAX_VKLAD 100000; ?

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
ingiraxo+15
Grafoman
22. 11. 2014   #13
-
0
-

#12 ondrej39
v té metodě pro nastavení čísla učtu použij tu metodu co jsem psal.. pokud bude true, tak nastavíš, pokud ne, tak vypíšeš třeba error... kontrolu na rozmezi čísla dělat nemusíš - je zbytečný (pokud teda nechceš speciální chybovou hlášku)

ano.. přes #define jak jsi psal.. klidne z té metody pro kontrolu učtu vyhod parametr string na název souboru a uvnitř použij definici z #define UCETNI_SOUBOR "ucty.txt"

Nahlásit jako SPAM
IP: 213.168.183.–
Moje aplikace: http://ophite.cz
Tutoriály na: C#
vitamin+8
Grafoman
22. 11. 2014   #14
-
0
-

Na ciselne konstanty sa hodi enum:

enum{MAX_VKLAD = 100000};
Nahlásit jako SPAM
IP: 95.105.229.–
obfuscate: "The cruel god Malloc will strike you down. "
ZMeson: "That's the C god. C++ has a new god. "
ondrej39+1
Věrný člen
22. 11. 2014   #15
-
0
-

#13 ingiraxo
Ale vždyť já někde musím mít ověřené to rozmezí zadávaného čísla účtu, číslo musí být v daném intervalu. Ta tvá bool metoda aktuálně hází true, když se zadávané číslo účtu shoduje již s existuuícím, takže po úprave setteru (setCisloUctu), aby pouze kontroloval, zda je zadávané číslo ve správném intervalu, můžu mít v mainu třeba toto (ber to opravdu pouze jako pseudokód)?

#include "stdafx.h"
#include <iostream>
#include <string>

#define UCTOVY_SOUBOR "ucty.txt";

int _tmain(int argc, _TCHAR* argv[])
{
	using namespace std;

	string soubor = UCTOVY_SOUBOR;
	Ucet *Ucet1 = new Ucet();

	int cisloUctu = 102345;

	while (jeUcetUplatny(soubor, cisloUctu))
	{
		cin >> cisloUctu;
	}
	Ucet1->setCisloUctu(cisloUctu);

	delete Ucet1;
}

EDIT: I když, jak nad tím přemýšlím, tady tímto postupem by člověk mohl nejdříve zadat třeba číslo 15, tím by se přeskočila podmínka (protože účet s číslem 15 určitě existovat nebude), vyvolal by se setter, ten by uživateli řekl, že zadané číslo není v intervalu a nyní by člověk mohl zadat číslo, které již v souboru existuje.

Takže bych to stejně musel vyřešit jinak.

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
ingiraxo+15
Grafoman
22. 11. 2014   #16
-
0
-

#15 ondrej39
ten interval je dobrý pouze pro optimalizaci, ale není nezbytně nutný pro správné fungování.. to podmínku pro interval přidej jako první do té metody na kontrolu platnosti účtu, ať to je pohromadě

potom můžeš brát něco jako (v main()) 

Ucet ucet1;
int cisloUctu;

while (true) {
   cout << "Zadej cislo uctu: ";
   cin >> cisloUctu;

  if (jeUcetPlatny(cisloUctu)) {
     ucet1.setCisloUctu(cisloUctu);
     break;
  } else {
     cout << "Ucet neni platny!";
  }
  cout << endl;
}

Takže celý by to vypadalo asi takto nějak 

#define MIN_ACC_NUM 100000
#define MAX_ACC_NUM 999999
#define ACCOUNTS_FILE "ucty.txt"

class Account
{
public:
    void setAccountNumber(int accNum)
    {
        accountNumber = accNum;
    }

    static bool isValid(int accNum)
    {
        if (accNum < MIN_ACC_NUM || accNum > MAX_ACC_NUM) return false;

        fstream f(ACCOUNTS_FILE);
        bool exist = false;
        string line;

        while (f.good()) {
            getline(f, line);

            if (line.length() == 0) break;
            int lineAccNum = atoi(line.substr(0, line.find(' ')).c_str());

            if (lineAccNum == accNum) {
                exist = true;
                break;
            }
        }
        f.close();
        return exist;
    }

private:
    int accountNumber;
};

int main()
{
    Account acc;
    int accNum;

    while (true) {
        cout << "Zadej cislo uctu: ";
        cin >> accNum;

        if (Account::isValid(accNum)) {
            acc.setAccountNumber(accNum);
            cout << "Cislo uctu " << accNum << " bylo nastaveno";
            break;
        } else {
            cout << "Cislo uctu " << accNum << " neni platne!";
        }
        cout << endl;
    }
    return EXIT_SUCCESS;
}

Ještě je možnost tu validaci dát přímo do settru s tím, že setter bude vracet bool, jestli validace prošla a potom while řídit přes validaci na setteru

Nahlásit jako SPAM
IP: 213.168.183.–
Moje aplikace: http://ophite.cz
Tutoriály na: C#
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 82 hostů

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032016 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý