Kapitel 4
Alle Codedateien dieses Kapitels herunterladen
04_6_1_IntegerZuStrings.cpp
/*
* Lösung für Übung 4.6.1 - Integer zu Strings
*/
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> toString(const std::vector<int>& list)
{
std::vector<std::string> result;
for (int element : list)
{
result.push_back(std::to_string(element));
}
return result;
}
int main()
{
std::vector<int> list = { 1, 2, 3 };
std::vector<std::string> stringList = toString(list);
// Ausgabe zum Testen
for (std::string element : stringList)
{
std::cout << element << std::endl;
}
return 0;
}
04_6_2_JoinMe.cpp
/*
* Lösung für Übung 4.6.2 - Join Me!
*/
#include <iostream>
#include <string>
#include <vector>
std::string join(const std::vector<std::string>& list, const std::string& delimiter)
{
std::string result;
for (int i = 0; i < list.size(); i++)
{
result += list.at(i);
// Das Trennzeichen nur einfügen, wenn es nicht das letzte Element ist
if (i < list.size() - 1)
{
result += delimiter;
}
}
return result;
}
int main()
{
std::vector<std::string> list = { "Mehl", "Salz", "Ei", "Butter" };
std::cout << join(list, ",") << std::endl;
std::cout << join(list, " - ") << std::endl;
return 0;
}
04_6_3_JoinMeAsWell.cpp
/*
* Lösung für Übung 4.6.3 - Join Me as well!
*/
#include <iostream>
#include <string>
#include <vector>
std::string join(const std::vector<std::string>& list, const std::string& delimiter)
{
std::string result;
for (int i = 0; i < list.size(); i++)
{
result += list.at(i);
// Das Trennzeichen nur einfügen, wenn es nicht das letzte Element ist
if (i < list.size() - 1)
{
result += delimiter;
}
}
return result;
}
std::string join(const std::vector<int>& list, const std::string& delimiter)
{
std::string result;
for (int i = 0; i < list.size(); i++)
{
result += std::to_string(list.at(i));
// Das Trennzeichen nur einfügen, wenn es nicht das letzte Element ist
if (i < list.size() - 1)
{
result += delimiter;
}
}
return result;
}
std::string join(const std::string input, const std::string& delimiter)
{
std::string result;
for (int i = 0; i < input.size(); i++)
{
result += input.at(i);
// Das Trennzeichen nur einfügen, wenn es nicht das letzte Element ist
if (i < input.size() - 1)
{
result += delimiter;
}
}
return result;
}
int main()
{
std::vector<std::string> list = { "Mehl", "Salz", "Ei", "Butter" };
std::cout << join(list, ",") << std::endl;
std::cout << join(list, " - ") << std::endl;
std::vector<int> intList = { 1, 2, 3, 5, 8 };
std::cout << join(intList, " -> ") << std::endl;
std::cout << join("abcdef", " ") << std::endl;
return 0;
}
04_6_4_WirHabenEinDate.cpp
/*
* Lösung für Übung 4.6.5. - Wir haben ein Date
*
* Die zwei neuen Funktionen heißen parseDate() und formatDate()
* und sind am Anfang der Datei zu finden.
* - parseDate() wird innerhalb von searchByDate() aufgerufen, nachdem
* die drei Zahlen einzeln vom Nutzer abgefragt wurden.
* - formatDate() wird gegen Ende der main()-Funktion benutzt, wenn
* die Suchergebnisse ausgegeben werden.
*
* Zusätzlich werden die Funktionen in einer extra Testfunktion
* testDateFunctions() aufgerufen, die testweise ein paar erwartete
* Ergebnisse vergleicht, um sicherzustellen dass die Funktionen
* sich verhalten wie erwartet. Das war nicht Teil der Aufgabenstellung,
* ist aber dennoch eine gute Idee.
*/
#include <string>
#include <vector>
#include <iostream>
#include <algorithm> // Für std::transform
int parseDate(int day, int month, int year)
{
return day + month * 100 + year * 10000;
}
std::string formatDate(int date)
{
return std::to_string(date % 100)
+ "." + std::to_string((date / 100) % 100)
+ "." + std::to_string(date / 10000);
}
bool checkTitlesAndDates(
const std::vector<std::string>& eventTitles,
const std::vector<int>& eventDates)
{
if (eventTitles.size() != eventDates.size())
{
// Das muss ein Programmierfehler sein
std::cerr << "Anzahl der Titel und Anzahl der Termine "
<< "muss gleich sein" << std::endl;
return false;
}
// Plausibilität: Hat das Datum exakt acht Stellen?
for (int date : eventDates)
{
if (date < 10000000 || date > 99999999)
{
std::cerr << "Falsches Datum: " << date << std::endl;
return false;
}
}
// Für die Suche muss das Datum sortiert sein
for (int i = 1; i < eventDates.size(); i++)
{
if (eventDates.at(i - 1) > eventDates.at(i))
{
std::cerr << "Termine nicht sortiert" << std::endl;
return false;
}
}
return true;
}
bool testDateFunctions()
{
/*
* Diese Funktion vergleicht ein paar Aufrufe der Datumsfunktionen
* mit den erwarteten Ergebnissen. Das soll mögliche Programmier-
* fehler finden.
*/
if (parseDate(3, 2, 2021) != 20210203)
{
std::cerr << "Fehler mit parseDate(3, 2, 2021)";
return false;
}
if (parseDate(22, 11, 2023) != 20231122)
{
std::cerr << "Fehler mit parseDate(22, 11, 2023)";
return false;
}
if (formatDate(20210203) != "3.2.2021")
{
std::cerr << "Fehler mit formatDate(20210203)";
return false;
}
if (formatDate(20231122) != "22.11.2023")
{
std::cerr << "Fehler mit formatDate(20231122)";
return false;
}
return true;
}
void showHeader(const std::string& text)
{
for (int i = 0; i < text.size(); i++)
{
std::cout << "#";
}
std::cout << std::endl << text << std::endl;
for (int i = 0; i < text.size(); i++)
{
std::cout << "#";
}
std::cout << std::endl;
}
int showSelection(const std::string& question,
const std::vector<std::string>& answers)
{
std::cout << question << std::endl;
for (int i = 0; i < answers.size(); i++)
{
std::cout << (i+1) << ": " << answers.at(i) << std::endl;
}
std::cout << "Tippen Sie eine Zahl ein: ";
int selection;
std::cin >> selection;
while (selection <= 0 || selection > answers.size())
{
std::cout << std::endl
<< "Eingabe inkorrekt. Bitte wiederholen: ";
std::cin >> selection;
}
std::cout << "----------------------------" << std::endl;
/*
* Der Nutzer hat eine Zahl zwischen 1 und der Anzahl der
* Elemente eingegeben. Als Programmierer erwarten wir
* aber, dass die Zählung bei 0 beginnt. Daher muss die
* 1 wieder abgezogen werden
*/
return selection - 1;
}
bool findInString(std::string text, std::string query)
{
/*
* Um Groß- und Kleinschreibung beim Suchen zu
* ignorieren, wandeln wir alles in Kleinbuchstaben um
*/
std::transform(text.begin(), text.end(),
text.begin(), tolower);
std::transform(query.begin(), query.end(),
query.begin(), tolower);
/*
* Mit .find() kann man innerhalb eines Strings nach
* einem anderen String suchen. Wenn er nicht gefunden
* wird, ist das Ergebnis std::string::npos (npos steht
* für "no position")
*/
return text.find(query) != std::string::npos;
}
std::vector<int> searchByTitle(
const std::vector<std::string>& titles)
{
std::cout << "Geben Sie ein Suchwort ein: ";
std::string query;
std::cin >> query;
std::vector<int> selections;
for (int i = 0; i < titles.size(); i++)
{
const std::string& title = titles.at(i);
if (findInString(title, query))
{
// Der Suchbegriff wurde im i-ten Titel gefunden
selections.push_back(i);
}
}
return selections;
}
std::vector<int> searchByDate(const std::vector<int>& dates)
{
/*
* Suche alle Termine, die an oder nach dem angegebenen
* Datum stattfinden.
*/
std::cout << "Bitte geben Sie ein Datum ein, ab dem "
<< "nach Veranstaltungen gesucht werden soll."
<< std::endl;
std::cout << "Tag: ";
int day;
std::cin >> day;
std::cout<< "Monat: ";
int month;
std::cin >> month;
std::cout << "Jahr: ";
int year;
std::cin >> year;
const int query = parseDate(day, month, year);
std::vector<int> selections;
for (int i = 0; i < dates.size(); i++)
{
const int& date = dates.at(i);
if (date >= query)
{
/*
* Dies ist das erste gefundene Datum, was nicht vor
* dem gesuchten Datum liegt. Daher geben wir alle
* übrigen Termine aus. Dafür starten wir eine neue
* for-Schleife beim i-ten Element und gehen von
* dort bis zum Ende der Liste.
*/
for (int j = i; j < dates.size(); j++)
{
selections.push_back(j);
}
// Schleife verlassen, da wir Termine gefunden haben
break;
}
}
return selections;
}
int main()
{
const std::vector<std::string> eventTitles = {
"Rock Concert",
"Jazz Concert",
"Hard-Rock Concert",
"Classical Concert",
"Jazz Concert"
};
// Speichern des Datums als JahrMonatTag, also YYYYMMDD
const std::vector<int> eventDates = {
20220417,
20220822,
20221011,
20221027,
20221203
};
if (!checkTitlesAndDates(eventTitles, eventDates))
{
// Fehlerhafter Datensatz
return 1;
}
if (!testDateFunctions())
{
// Fehlerhafte Datumsfunktionen
return 1;
}
showHeader("Willkommen beim digitalen Buchungssystem");
const std::vector<std::string> searchTypes = {
"nach Titel der Veranstaltung",
"nach Termin der Veranstaltung"
};
const int selectedSearch = showSelection(
"Wie wollen Sie suchen?",
searchTypes);
std::vector<int> eventsFound;
switch (selectedSearch) {
case 0:
eventsFound = searchByTitle(eventTitles);
break;
case 1:
eventsFound = searchByDate(eventDates);
break;
default:
std::cerr << "Unerwarteter searchType: "
<< selectedSearch << std::endl;
return 1;
}
if (eventsFound.size() == 0)
{
showHeader("Leider keine Veranstaltung gefunden");
}
else
{
showHeader("Veranstaltungen gefunden:");
std::vector<std::string> selectionTexts;
for (int index : eventsFound)
{
selectionTexts.push_back(eventTitles.at(index)
+ ", am " + formatDate(eventDates.at(index)));
}
int selected = showSelection(
"Welche Veranstaltung wollen Sie buchen?",
selectionTexts);
showHeader("Sie haben gebucht: "
+ selectionTexts.at(selected));
}
return 0;
}
04_6_5_DieSucheVerbessern.cpp
/*
* Lösung für Übung 4.6.6 Die Suche verbessern
*
* Den Verarbeitungsschritt finden Sie in der Funktion findInString().
*/
#include <string>
#include <vector>
#include <iostream>
#include <algorithm> // Für std::transform
bool checkTitlesAndDates(
const std::vector<std::string>& eventTitles,
const std::vector<int>& eventDates)
{
if (eventTitles.size() != eventDates.size())
{
// Das muss ein Programmierfehler sein
std::cerr << "Anzahl der Titel und Anzahl der Termine "
<< "muss gleich sein" << std::endl;
return false;
}
// Plausibilität: hat das Datum exakt acht Stellen?
for (int date : eventDates)
{
if (date < 10000000 || date > 99999999)
{
std::cerr << "Falsches Datum: " << date << std::endl;
return false;
}
}
// Für die Suche muss das Datum sortiert sein
for (int i = 1; i < eventDates.size(); i++)
{
if (eventDates.at(i - 1) > eventDates.at(i))
{
std::cerr << "Termine nicht sortiert" << std::endl;
return false;
}
}
return true;
}
void showHeader(const std::string& text)
{
for (int i = 0; i < text.size(); i++)
{
std::cout << "#";
}
std::cout << std::endl << text << std::endl;
for (int i = 0; i < text.size(); i++)
{
std::cout << "#";
}
std::cout << std::endl;
}
int showSelection(const std::string& question,
const std::vector<std::string>& answers)
{
std::cout << question << std::endl;
for (int i = 0; i < answers.size(); i++)
{
std::cout << (i+1) << ": " << answers.at(i) << std::endl;
}
std::cout << "Tippen Sie eine Zahl ein: ";
int selection;
std::cin >> selection;
while (selection <= 0 || selection > answers.size())
{
std::cout << std::endl
<< "Eingabe inkorrekt. Bitte wiederholen: ";
std::cin >> selection;
}
std::cout << "----------------------------" << std::endl;
/*
* Der Nutzer hat eine Zahl zwischen 1 und der Anzahl der
* Elemente eingegeben. Als Programmierer erwarten wir
* aber, dass die Zählung bei 0 beginnt. Daher muss die
* 1 wieder abgezogen werden
*/
return selection - 1;
}
bool findInString(std::string text, std::string query)
{
/*
* Um Groß- und Kleinschreibung beim Suchen zu
* ignorieren, wandeln wir alles in Kleinbuchstaben um
*/
std::transform(text.begin(), text.end(),
text.begin(), tolower);
std::transform(query.begin(), query.end(),
query.begin(), tolower);
/*
* Entferne Sonderzeichen (Bindestrich und Leerzeichen)
* aus dem Veranstaltungstitel und der Suchanfrage
*/
std::string textSanitized;
for (char c : text)
{
if (c != '-' && c != ' ')
{
textSanitized += c;
}
}
std::string querySanitized;
for (char c : query)
{
if (c != '-' && c != ' ')
{
querySanitized += c;
}
}
/*
* Mit .find() kann man innerhalb eines Strings nach
* einem anderen String suchen. Wenn er nicht gefunden
* wird, ist das Ergebnis std::string::npos (npos steht
* für "no position"). Hier prüfen wir darauf, ob er gefunden
* wurde und wenn ja, geben true zurück.
*/
return textSanitized.find(querySanitized) != std::string::npos;
}
std::vector<int> searchByTitle(
const std::vector<std::string>& titles)
{
std::cout << "Geben Sie ein Suchwort ein: ";
std::string query;
std::cin >> query;
std::vector<int> selections;
for (int i = 0; i < titles.size(); i++)
{
const std::string& title = titles.at(i);
if (findInString(title, query))
{
// Der Suchbegriff wurde im i-ten Titel gefunden
selections.push_back(i);
}
}
return selections;
}
std::vector<int> searchByDate(const std::vector<int>& dates)
{
/*
* Suche alle Termine, die an oder nach dem angegebenen
* Datum stattfinden.
*/
std::cout << "Bitte geben Sie ein Datum ein, ab dem "
<< "nach Veranstaltungen gesucht werden soll."
<< std::endl << "Geben Sie das Datum im Format "
<< "YYYYMMDD ein, also z.B. 20210705: ";
int query;
std::cin >> query;
std::vector<int> selections;
for (int i = 0; i < dates.size(); i++)
{
const int& date = dates.at(i);
if (date >= query)
{
/*
* Dies ist das erste gefundene Datum, was nicht vor
* dem gesuchten Datum liegt. Daher geben wir alle
* übrigen Termine aus. Dafür starten wir eine neue
* for-Schleife beim i-ten Element und gehen von
* dort bis zum Ende der Liste.
*/
for (int j = i; j < dates.size(); j++)
{
selections.push_back(j);
}
// Schleife verlassen, da wir Termine gefunden haben
break;
}
}
return selections;
}
int main()
{
const std::vector<std::string> eventTitles = {
"Rock Concert",
"Jazz Concert",
"Hard-Rock Concert",
"Classical Concert",
"Jazz Concert"
};
// Speichern des Datums als JahrMonatTag, also YYYYMMDD
const std::vector<int> eventDates = {
20220417,
20220822,
20221011,
20221027,
20221203
};
if (!checkTitlesAndDates(eventTitles, eventDates))
{
// Fehlerhafter Datensatz
return 1;
}
showHeader("Willkommen beim digitalen Buchungssystem");
const std::vector<std::string> searchTypes = {
"nach Titel der Veranstaltung",
"nach Termin der Veranstaltung"
};
const int selectedSearch = showSelection(
"Wie wollen Sie suchen?",
searchTypes);
std::vector<int> eventsFound;
switch (selectedSearch) {
case 0:
eventsFound = searchByTitle(eventTitles);
break;
case 1:
eventsFound = searchByDate(eventDates);
break;
default:
std::cerr << "Unerwarteter searchType: "
<< selectedSearch << std::endl;
return 1;
}
if (eventsFound.size() == 0)
{
showHeader("Leider keine Veranstaltung gefunden");
}
else
{
showHeader("Veranstaltungen gefunden:");
std::vector<std::string> selectionTexts;
for (int index : eventsFound)
{
selectionTexts.push_back(eventTitles.at(index)
+ ", am " + std::to_string(eventDates.at(index)));
}
int selected = showSelection(
"Welche Veranstaltung wollen Sie buchen?",
selectionTexts);
showHeader("Sie haben gebucht: "
+ selectionTexts.at(selected));
}
return 0;
}
04_6_6_NochNeRundeRueckwaerts.cpp
/*
* Lösung für Übung 4.6.7 Noch 'ne Runde rückwärts
*
* Hier können Sie sehen, dass eine rekursive Implementierung
* nicht immer einfacher und schöner sein muss als eine
* iterative. Letztendlich ist es Geschmackssache, aber ich
* persönlich finde invertIterative() einfacher zu lesen als
* invert()
*/
#include <iostream>
#include <string>
std::string invert(const std::string& text)
{
if (text.size() == 0)
{
return "";
}
return invert(text.substr(1)) + text.at(0);
}
std::string invertIterative(const std::string& text)
{
std::string result;
for (char c : text)
{
result = c + result;
}
return result;
}
int main()
{
std::cout << invert("Ein Text") << std::endl;
std::cout << invertIterative("Ein Text") << std::endl;
return 0;
}