Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: C++: Tiedoston rivien käsittely

Teuro [03.11.2009 18:01:21]

#

Pelejä ohjelmoitaessa tallennetaan pelitiedot usein tiedostoon, josta ne ladataan käyttöön. PHP:ä ohjelmoijat tietävätkin file funktion, joka tekee tiedoston riveistä taulukon. Samaten funktio explode on useimmille tuttu. Se "räjäyttää" annetun merkkijonon annettujen katkaisumerkkien kohdalta osiin. Tähän koodivinkkiin olen tehnyt vastaavat toteutukset C++ kielellä.

#include "funktiot.hpp"

/**
	* Lataa muistiin tiedoston rivit
	* palauttaa vektorin, jossa jokainen tiedoston rivi on oma solunsa
	* heittää virheen, jos tiedostoa ei löydy tai se ei aukea
*/

std::vector <std::string> file(std::string nimi){
	std::vector <std::string> tmp_rivit;

	std::string tmp;
	std::ifstream sisaan(nimi.c_str());

	if(!sisaan){
		throw std::logic_error("Tiedostoa " + nimi + "ei ole, tai se ei aukea");
	}

	while(sisaan){
		getline(sisaan, tmp);
		tmp_rivit.push_back(tmp);
	}

	sisaan.close();
	return tmp_rivit;
}

/**
	* Purkaa annetun rivin osiin, jossa käyttäjä voi itse päättää erottimen
	* Heittää virheen, jos annettua erotinta ei löydy
*/

std::vector<std::string> explode(std::string erotin, std::string rivi){
	std::vector <std::string> tmp_solut;
	std::string temppi = "";

	while(rivi.length()){
		std::string::size_type pos = rivi.find(erotin, 0);

		if (pos == std::string::npos){
			throw std::logic_error("Rivi ei tue " + erotin + " erotinta");
		}

		temppi = rivi.substr(0, pos);

		rivi.erase(0, pos+1);

		tmp_solut.push_back(temppi);
	}
	return tmp_solut;
}

main.cpp

#include <iostream>
#include <vector>
#include <stdexcept>
#include "funktiot.hpp"

std::vector <std::string> Rivit;
std::vector <std::string> Solut;

int main(){
    try{
        Rivit = file("tiedot.txt");
    }catch(std::exception &virhe){
        std::cout << virhe.what() << std::endl;
    }

    for(unsigned int a = 0; a < Rivit.size(); a++){
        try{
            Solut = explode("|", Rivit[a]);
            for(unsigned int b = 0; b < Solut.size(); b++){
                std::cout << Solut[b] << " ";
            }
            std::cout << std::endl;
        }catch(std::exception &virhe){
            std::cout << virhe.what() << std::endl;
        }
    }

    return EXIT_SUCCESS;
}

tiedot.txt

Juha|Helsinki|30.5|13
Pekka|Vantaa|15.32|4
Janne|Sipoo|28.57|8
Riikka|Tuusula|26.37|13

Metabolix [15.11.2010 16:55:16]

#

File-funktio laittaa loppuun ylimääräisen tyhjän rivin. While-silmukan ehdossa pitäisi yrittää ensin lukea merkki ja sitten vasta tarkistaa, onko tiedosto loppu:

while (sisaan.peek(), (sisaan.good() && !sisaan.eof()))

Explode-funktiossa on ilmiselvä virhe: jos rivi ei pääty erotinmerkkiin, koodi heittää poikkeuksen. Muutenkin on outoa käytöstä, että erotinmerkitön rivi aiheuttaisi virheen. Järkevämmin funktion silmukka menisi näin:

while (true) {
    std::string::size_type pos = rivi.find(erotin, 0);
    if (pos == std::string::npos) {
        tmp_solut.push_back(rivi);
        return tmp_solut;
    }
    tmp_solut.push_back(rivi.substr(0, pos));
    rivi.erase(0, pos + 1);
}

Turhasta apumuuttujastakin päästiin samalla eroon.

Kaiken kukkuraksi vinkistä puuttuu funktiot.hpp ja ainakin GCC:n Linux-version mukaan useita include-rivejä (string, fstream, cstdlib).

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta