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
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).
Aihe on jo aika vanha, joten et voi enää vastata siihen.