Bündle Dateilesefunktionalität in extra Datei, damit es von mehreren Programmen verwe...
authorAndreas Bilke <andreas@bilke.org>
Sun, 30 Jul 2017 14:04:48 +0000 (16:04 +0200)
committerAndreas Bilke <andreas@bilke.org>
Sun, 30 Jul 2017 14:04:48 +0000 (16:04 +0200)
Quiz/cpp/Makefile
Quiz/cpp/quiz.cpp
common/cpp/file.cpp [new file with mode: 0644]
common/cpp/file.hpp [new file with mode: 0644]

index 83f67bc..4ce9041 100644 (file)
@@ -1,5 +1,5 @@
 all:
-       g++ -Wall -o quiz quiz.cpp
+       g++ -Wall -o quiz ../../common/cpp/file.cpp quiz.cpp
 
 clean:
        -rm quiz
index f3f37cf..517ee74 100644 (file)
@@ -6,11 +6,12 @@
  * \copyright GNU Public License
  */
 
+#include "../../common/cpp/file.hpp"
+
 #include <cstdlib>
 
 #include <algorithm>
 #include <exception>
-#include <fstream>
 #include <iostream>
 #include <stdexcept>
 #include <string>
@@ -26,10 +27,10 @@ class FrageAntworten {
     private:
         /*! Die zu stellende Frage */
         std::string frage;
-        /*! Die Position der korrekten Antwort in \ref antworten */
-        unsigned int korrekteantwort;
         /*! Eine Liste von Antwortmöglichkeiten */
         std::vector<std::string> antworten;
+        /*! Die Position der korrekten Antwort in \ref antworten */
+        unsigned int korrekteantwort;
 
     public:
         /*!
@@ -86,8 +87,7 @@ class FrageAntworten {
         }
 };
 
-std::vector<FrageAntworten> liesDatei(std::string& dateiname);
-std::vector<std::string> teileZeile(std::string& zeile);
+std::vector<FrageAntworten> erstelleFrageAntworten(std::vector<std::vector<std::string>> zeilen);
 
 /*!
  * \brief Einstiegspunkt für das Programm "quiz".
@@ -103,7 +103,7 @@ int main(int argc, char** argv) {
     }
 
     std::string quizdatei = std::string(argv[1]);
-    std::vector<FrageAntworten> frageantworten = liesDatei(quizdatei);
+    std::vector<FrageAntworten> frageantworten = erstelleFrageAntworten(liesDatei(quizdatei));
 
     std::vector<size_t> fragenreihenfolge(frageantworten.size());
     for (size_t i = 0; i < frageantworten.size(); i++) {
@@ -127,73 +127,41 @@ int main(int argc, char** argv) {
 }
 
 /*!
- * \brief Liest die Datei zeilenweise und extrahiert die Fragen/Antworten
+ * \brief Extrahiert Fragen/Antworten aus dem std::vector
  *
- * Öffnet die Datei und liest die Datei zeilenweise. Das Format
- * der Datei ist dabei
+ * \ref zeilen enthält die nach ";" getrennten Zeilen einer Datei. Erwartet wird dabei folgendes Format:
  *
  * Frage;korrekte Antwort als Position;Antwortmöglichkeit 1;Antwortmöglichkeit 2 etc
  *
- * Das Format ist dabei eine CSV Datei mit ";" als Trennzeichen.
- *
- * \param dateiname Der Dateiname (mit Pfad) zur Datei mit den Fragen/Antworten
- * \return Ein std::vector mit FrageAntworten Objekten.
+ * \param zeilen die gesamte Datei zeilenweise gespeichert, jede Zeile nach ";" getrennt
  */
-std::vector<FrageAntworten> liesDatei(std::string& dateiname) {
-    std::ifstream dateistream(dateiname);
-    if (!dateistream.good()) {
-       throw std::ios_base::failure("Kann Datei nicht lesen.");
-    }
-
+std::vector<FrageAntworten> erstelleFrageAntworten(std::vector<std::vector<std::string>> zeilen) {
     std::vector<FrageAntworten> frageantworten;
-
-    std::string zeile;
-    while (std::getline(dateistream, zeile).good()) {
-        std::vector<std::string> getrennteElemente = teileZeile(zeile);
-        if (getrennteElemente.size() < 3) {
+    for (auto zeile : zeilen) {
+        if (zeile.size() < 3) {
             throw std::logic_error("Das Dateiformat stimmt nicht. Es muss pro Zeile Eine Frage, eine korrekte Antwort und mindestens eine Antwortmöglichkeit geben.");
         }
 
         // Dreht den vector mit den Spalten um, damit Frage und korrekte Antwort
         // von hinten mittels back (und dann mit pop_back gelöscht) werden können.
-        std::reverse(getrennteElemente.begin(), getrennteElemente.end());
+        std::reverse(zeile.begin(), zeile.end());
 
-        std::string frage = getrennteElemente.back();
-        getrennteElemente.pop_back();
-        unsigned int korrekteantwort = std::stoi(getrennteElemente.back());
-        getrennteElemente.pop_back();
+        std::string frage = zeile.back();
+        zeile.pop_back();
+        unsigned int korrekteantwort = std::stoi(zeile.back());
+        zeile.pop_back();
 
-        if (korrekteantwort < 0 || korrekteantwort >= getrennteElemente.size()) {
+        if (korrekteantwort < 0 || korrekteantwort >= zeile.size()) {
             throw std::logic_error("Das Dateiformat stimmt nicht. Die Angabe der korrekten Antwort referenziert auf eine nicht existierende Antwortmöglichkeit in der Datei.");
         }
 
         // Stellt die ursprüngliche Reihenfolge wieder her, damit die
         // Position der korrekten Antwort passt.
-        std::reverse(getrennteElemente.begin(), getrennteElemente.end());
-        FrageAntworten frageantwort = FrageAntworten(frage, getrennteElemente, korrekteantwort);
+        std::reverse(zeile.begin(), zeile.end());
+        FrageAntworten frageantwort = FrageAntworten(frage, zeile, korrekteantwort);
 
         frageantworten.push_back(frageantwort);
     }
 
     return frageantworten;
 }
-
-/*!
- * \brief Trennt einen String am ";" Zeichen und erstellt daraus einen std::vector
- *
- * \return Die einzelnen Spalten aus dem CSV std::string
- */
-std::vector<std::string> teileZeile(std::string& zeile) {
-    std::string::size_type letztePos = zeile.find_first_not_of(";", 0);
-    std::string::size_type pos = zeile.find_first_of(";", letztePos);
-
-    std::vector<std::string> getrennteElemente;
-
-    while (std::string::npos != pos || std::string::npos != letztePos)  {
-        getrennteElemente.push_back(zeile.substr(letztePos, pos - letztePos));
-        letztePos = zeile.find_first_not_of(";", pos);
-        pos = zeile.find_first_of(";" , letztePos);
-    }
-
-    return getrennteElemente;
-}
diff --git a/common/cpp/file.cpp b/common/cpp/file.cpp
new file mode 100644 (file)
index 0000000..4bac361
--- /dev/null
@@ -0,0 +1,35 @@
+#include "file.hpp"
+
+#include <fstream>
+
+std::vector<std::vector<std::string>> liesDatei(std::string& dateiname) {
+    std::ifstream dateistream(dateiname);
+    if (!dateistream.good()) {
+       throw std::ios_base::failure("Kann Datei nicht lesen.");
+    }
+
+    std::vector<std::vector<std::string>> zeilen;
+
+    std::string zeile;
+    while (std::getline(dateistream, zeile).good()) {
+        std::vector<std::string> getrenneZeile = teileZeile(zeile);
+        zeilen.push_back(getrenneZeile);
+    }
+
+    return zeilen;
+}
+
+std::vector<std::string> teileZeile(std::string& zeile) {
+    std::string::size_type letztePos = zeile.find_first_not_of(";", 0);
+    std::string::size_type pos = zeile.find_first_of(";", letztePos);
+
+    std::vector<std::string> getrennteElemente;
+
+    while (std::string::npos != pos || std::string::npos != letztePos)  {
+        getrennteElemente.push_back(zeile.substr(letztePos, pos - letztePos));
+        letztePos = zeile.find_first_not_of(";", pos);
+        pos = zeile.find_first_of(";" , letztePos);
+    }
+
+    return getrennteElemente;
+}
diff --git a/common/cpp/file.hpp b/common/cpp/file.hpp
new file mode 100644 (file)
index 0000000..afab7d5
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef FILE_H_
+#define FILE_H_
+
+#include <string>
+#include <vector>
+
+/*!
+ * \brief Liest die Datei zeilenweise und extrahiert die Spalten
+ *
+ * Öffnet die Datei und liest die CSV Datei zeilenweise.
+ *
+ * \param dateiname Der Dateiname (mit Pfad) zur Datei
+ * \return Ein std::vector mit (nach ";") getrennten Zeilen
+ */
+std::vector<std::vector<std::string>> liesDatei(std::string& dateiname);
+
+/*!
+ * \brief Trennt einen String am ";" Zeichen und erstellt daraus einen std::vector
+ *
+ * \return Die einzelnen Spalten aus dem CSV std::string
+ */
+std::vector<std::string> teileZeile(std::string& zeile);
+
+#endif