Kapitel 4

Alle Codedateien dieses Kapitels herunterladen

04_6_1_IntegerZuStrings.cpp

Datei herunterladen

/*
 * 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

Datei herunterladen

/*
 * 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

Datei herunterladen

/*
 * 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

Datei herunterladen

/*
 * 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

Datei herunterladen

/*
 * 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

Datei herunterladen

/*
 * 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;
}