Die Boost C++ Bibliotheken

Kapitel 5. Boost.StringAlgorithms

Die Bibliothek Boost.StringAlgorithms stellt viele freistehende Funktionen im Namensraum boost::algorithm zur Verfügung, mit denen sich Strings verarbeiten lassen. Strings können dabei vom Typ std::string, std::wstring oder einer anderen Instanz der Template-Klasse std::basic_string sein. Dazu zählen auch die mit C++11 eingeführten Klassen std::u16string und std::u32string.

Alle Funktionen sind je nach Kategorie in unterschiedlichen Headerdateien definiert. So muss, um auf Funktionen zum Umwandeln von Groß- und Kleinbuchstaben zuzugreifen, die Headerdatei boost/algorithm/string/case_conv.hpp eingebunden werden. Weil Boost.StringAlgorithms mehr als 20 Kategorien und somit ebenso viele Headerdateien anbietet, steht mit boost/algorithm/string.hpp eine Master-Headerdatei zur Verfügung, die alle anderen einbindet.

Beispiel 5.1. String in Großbuchstaben umwandeln
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::string s = "Boost C++ Libraries";
  std::cout << to_upper_copy(s) << '\n';
}

Die Funktion boost::algorithm::to_upper_copy() kann verwendet werden, um einen String in Großbuchstaben zu konvertieren. Neben dieser Funktion stellt Boost.StringAlgorithms auch boost::algorithm::to_lower_copy() zur Verfügung, um einen String in Kleinbuchstaben umzuwandeln. Beide Funktionen geben den umgewandelten String als Ergebnis zurück. Soll der String selbst, der als Parameter an die Funktion übergeben wird, umgewandelt werden, müssen boost::algorithm::to_upper() oder boost::algorithm::to_lower() aufgerufen werden.

Im Beispiel 5.1 wird der String Boost C++ Libraries mit boost::algorithm::to_upper_copy() in Großbuchstaben umgewandelt. Wenn Sie das Beispiel ausführen, wird BOOST C++ LIBRARIES ausgegeben.

Die von Boost.StringAlgorithms angebotenen Funktionen berücksichtigen Locales. Funktionen wie boost::algorithm::to_upper_copy() verwenden das globale Locale, um einen String in Großbuchstaben umzuwandeln, wenn ein Locale nicht explizit als Parameter übergeben wird.

Beispiel 5.2. String mit einem Locale in Großbuchstaben umwandeln
#include <boost/algorithm/string.hpp>
#include <string>
#include <locale>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::string s = "Boost C++ k\xfct\xfcphaneleri";
  std::string upper_case1 = to_upper_copy(s);
  std::string upper_case2 = to_upper_copy(s, std::locale{"Turkish"});
  std::locale::global(std::locale{"Turkish"});
  std::cout << upper_case1 << '\n';
  std::cout << upper_case2 << '\n';
}

Im Beispiel 5.2 wird boost::algorithm::to_upper_copy() zweimal aufgerufen, um den String Boost C++ kütüphaneleri in Türkisch in Großbuchstaben umzuwandeln. Der erste Aufruf von boost::algorithm::to_upper_copy() verwendet das globale Locale. Da das globable Locale im Beispiel vor dem ersten Aufruf von boost::algorithm::to_upper_copy() nicht geändert wurde, ist dies das C-Locale. Da der zu umwandelnde String Umlaute enthält, die für das C-Locale keine Buchstaben sind, wird als Ergebnis für den ersten Aufruf von boost::algorithm::to_upper_copy() BOOST C++ KüTüPHANELERI ausgegeben.

Der zweite Aufruf findet mit einem Locale für den türkischen Kulturkreis statt. Die Umlaute werden in diesem Fall in Großbuchstaben umgewandelt. Als Ergebnis wird für den zweiten Aufruf von boost::algorithm::to_upper_copy() BOOST C++ KÜTÜPHANELERI ausgegeben.

Anmerkung

Ersetzen Sie die Angabe Turkish mit tr_TR, wenn Sie das Beispiel auf einem POSIX-Betriebssystem ausführen möchten. Stellen Sie außerdem sicher, dass das Locale für den türkischen Sprach- und Kulturkreis installiert ist.

Beispiel 5.3. String-Algorithmen, um Zeichen in einem String zu löschen
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::string s = "Boost C++ Libraries";
  std::cout << erase_first_copy(s, "s") << '\n';
  std::cout << erase_nth_copy(s, "s", 0) << '\n';
  std::cout << erase_last_copy(s, "s") << '\n';
  std::cout << erase_all_copy(s, "s") << '\n';
  std::cout << erase_head_copy(s, 5) << '\n';
  std::cout << erase_tail_copy(s, 9) << '\n';
}

Boost.StringAlgorithms stellt wie im Beispiel 5.3 zu sehen mehrere Funktionen zur Verfügung, um Zeichen in einem String zu löschen. Dabei kann auf unterschiedliche Weise angegeben werden, welcher Teil eines Strings gelöscht werden soll. So kann zum Beispiel mit boost::algorithm::erase_all_copy() der Buchstabe s aus einem String komplett oder mit boost::algorithm::erase_first_copy() nur das erste s gelöscht werden. Außerdem stehen mit boost::algorithm::erase_head_copy() und boost::algorithm::erase_tail_copy() Funktionen zur Verfügung, die den Anfang oder das Ende eines Strings um eine bestimmte Anzahl an Zeichen kürzen.

Beispiel 5.4. Mit boost::algorithm::find_first() nach Substrings suchen
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::string s = "Boost C++ Libraries";
  boost::iterator_range<std::string::iterator> r = find_first(s, "C++");
  std::cout << r << '\n';
  r = find_first(s, "xyz");
  std::cout << r << '\n';
}

Verschiedene Funktionen wie boost::algorithm::find_first() stehen zur Verfügung, um Strings nach einem Substring zu durchsuchen. So kann auch mit boost::algorithm::find_last(), boost::algorithm::find_nth(), boost::algorithm::find_head() und boost::algorithm::find_tail() nach Substrings gesucht werden.

Allen genannten Funktionen ist gemein, dass sie ein paar Paar Iteratoren zurückgeben. Dieses Paar hat den Typ boost::iterator_range. Diese Klasse stammt aus der Bibliothek Boost.Range, die basierend auf dem Iterator-Konzept ein Range-Konzept definiert. Da der Operator operator<< für boost::iterator_range überladen ist, kann das Ergebnis der Suchalgorithmen direkt auf die Standardausgabe ausgegeben werden. So wird im Beispiel 5.4 als erstes Ergebnis C++ und als zweites Ergebnis ein leerer String ausgegeben.

Beispiel 5.5. Strings mit boost::algorithm::join() verketten
#include <boost/algorithm/string.hpp>
#include <string>
#include <vector>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::vector<std::string> v{"Boost", "C++", "Libraries"};
  std::cout << join(v, " ") << '\n';
}

Der Funktion boost::algorithm::join() wird als erster Parameter ein Container mit Strings übergeben. Die Funktion hängt die Strings im Container aneinander und fügt zwischen zwei Strings jeweils den String ein, der als zweiter Parameter übergeben wird. So gibt Beispiel 5.5 Boost C++ Libraries aus.

Beispiel 5.6. String-Algorithmen, um Zeichen in einem String zu ersetzen
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::string s = "Boost C++ Libraries";
  std::cout << replace_first_copy(s, "+", "-") << '\n';
  std::cout << replace_nth_copy(s, "+", 0, "-") << '\n';
  std::cout << replace_last_copy(s, "+", "-") << '\n';
  std::cout << replace_all_copy(s, "+", "-") << '\n';
  std::cout << replace_head_copy(s, 5, "BOOST") << '\n';
  std::cout << replace_tail_copy(s, 9, "LIBRARIES") << '\n';
}

So wie Boost.StringAlgorithms mehrere Funktionen zur Verfügung stellt, um Strings zu durchsuchen oder eine Zeichenkette in Strings zu löschen, stehen auch Funktionen zur Verfügung, um eine Zeichenkette in einem String mit einer anderen Zeichenkette zu ersetzen. Zu diesen Funktionen zählen boost::algorithm::replace_first_copy(), boost::algorithm:: replace_nth_copy(), boost::algorithm::replace_last_copy(), boost::algorithm::replace_all_copy(), boost::algorithm::replace_head_copy() und boost::algorithm::replace_tail_copy(). Wie im Beispiel 5.6 zu sehen, werden diese Funktionen genauso angewandt wie die Funktionen zum Suchen und Löschen von Zeichenketten. Der einzige Unterschied ist, dass sie einen zusätzlichen Parameter erwarten – die Zeichenkette, die die gesuchte ersetzen soll.

Beispiel 5.7. String-Algorithmen, um Strings zu trimmen
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::string s = "\t Boost C++ Libraries \t";
  std::cout << "_" << trim_left_copy(s) << "_\n";
  std::cout << "_" << trim_right_copy(s) << "_\n";
  std::cout << "_" << trim_copy(s) << "_\n";
}

Wenn eine Zeichenkette an Anfang und Ende automatisch um Leerzeichen gekürzt werden soll, können wie im Beispiel 5.7 die Funktionen boost::algorithm::trim_left_copy(), boost::algorithm::trim_right_copy() und boost::algorithm::trim_copy() verwendet werden. Welche Zeichen als Leerzeichen gelten, hängt vom globalen Locale ab.

Für verschiedene Funktionen ermöglicht Boost.StringAlgorithms, als zusätzlichen Parameter ein Prädikat zu übergeben, von dem abhängt, auf welche Zeichen in einem String die Funktion angewandt wird. So stehen neben den eben genannten drei Funktionen boost::algorithm::trim_left_copy_if(), boost::algorithm::trim_right_copy_if() und boost::algorithm::trim_copy_if() zur Verfügung.

Beispiel 5.8. Prädikate mit boost::algorithm::is_any_of() erstellen
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::string s = "--Boost C++ Libraries--";
  std::cout << trim_left_copy_if(s, is_any_of("-")) << '\n';
  std::cout << trim_right_copy_if(s, is_any_of("-")) << '\n';
  std::cout << trim_copy_if(s, is_any_of("-")) << '\n';
}

Im Beispiel 5.8 wird zusätzlich auf die Funktion boost::algorithm::is_any_of() zugegriffen. Es handelt sich hierbei um eine Hilfsfunktion, mit der ein Prädikat erstellt wird, das überprüft, ob ein Zeichen in dem String vorkommt, der als Parameter an boost::algorithm::is_any_of() übergeben wird. Mit Hilfe von boost::algorithm::is_any_of() kann angegeben werden, um welche Zeichen ein String getrimmt werden soll. Im Beispiel 5.8 ist das der Bindestrich.

Boost.StringAlgorithms stellt zahlreiche Hilfsfunktionen zur Verfügung, die häufig benötigte Prädikate zurückgeben.

Beispiel 5.9. Prädikate mit boost::algorithm::is_digit() erstellen
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::string s = "123456789Boost C++ Libraries123456789";
  std::cout << trim_left_copy_if(s, is_digit()) << '\n';
  std::cout << trim_right_copy_if(s, is_digit()) << '\n';
  std::cout << trim_copy_if(s, is_digit()) << '\n';
}

Das Prädikat, das von boost::algorithm::is_digit() zurückgegeben wird, gibt für alle Ziffern true zurück. So werden im Beispiel 5.9 Ziffern aus dem String s entfernt.

Neben boost::algorithm::is_digit() stehen mit boost::algorithm::is_upper() und boost::algorithm::is_lower() Hilfsfunktionen zur Verfügung, die Zeichen auf Groß- und Kleinschreibung überprüfen. All diese Funktionen verwenden das globale Locale, wenn kein Locale explizit als Parameter übergeben wird.

Beispiel 5.10. String-Algorithmen, um Strings mit anderen zu vergleichen
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::string s = "Boost C++ Libraries";
  std::cout.setf(std::ios::boolalpha);
  std::cout << starts_with(s, "Boost") << '\n';
  std::cout << ends_with(s, "Libraries") << '\n';
  std::cout << contains(s, "C++") << '\n';
  std::cout << lexicographical_compare(s, "Boost") << '\n';
}

Neben den Prädikaten, die mit Hilfe der eben vorgestellten Hilfsfunktionen erstellt werden und die einzelne Zeichen überprüfen, bietet Boost.StringAlgorithms Funktionen an, mit denen Strings überprüft werden können.

Die Funktionen boost::algorithm::starts_with(), boost::algorithm::ends_with(), boost::algorithm::contains() und boost::algorithm::lexicographical_compare() können wie im Beispiel 5.10 aufgerufen werden, um zwei Strings miteinander zu vergleichen.

Beispiel 5.11. Strings mit boost::algorithm::split() teilen
#include <boost/algorithm/string.hpp>
#include <string>
#include <vector>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::string s = "Boost C++ Libraries";
  std::vector<std::string> v;
  split(v, s, is_space());
  std::cout << v.size() << '\n';
}

Die Funktion boost::algorithm::split() wird verwendet, um einen String an bestimmten Stellen in seine Teile zu zerlegen und diese in einem Container zu speichern. Der Funktion muss als dritter Parameter ein Prädikat übergeben werden, das für jedes Zeichen entscheidet, ob der String an dieser Stelle geteilt werden soll oder nicht. Hier können die von Boost.StringAlgorithms zur Verfügung gestellten Hilfsfunktionen verwendet werden, die Prädikate zurückgeben. Im Beispiel 5.11 wird auf boost::algorithm::is_space() zugegriffen, so dass der String an Leerzeichen gesplittet wird.

Viele der Funktionen, die Sie in diesem Kapitel kennengelernt haben, existieren auch in einer Variante, die Groß- und Kleinschreibung ignoriert. Diese Funktionen haben typischerweise den gleichen Namen, beginnen aber mit einem i. So heißt die zu boost::algorithm::erase_all_copy() entsprechende Funktion, die Zeichenketten unabhängig von Groß- und Kleinschreibung löscht, boost::algorithm::ierase_all_copy().

Abschließend soll erwähnt werden, dass Boost.StringAlgorithms für mehrere Funktionen auch reguläre Ausdrücke unterstützt. So wird im Beispiel 5.12 mit boost::algorithm::find_regex() nach einem regulären Ausdruck gesucht.

Beispiel 5.12. Strings mit boost::algorithm::find_regex() durchsuchen
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex.hpp>
#include <string>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::string s = "Boost C++ Libraries";
  boost::iterator_range<std::string::iterator> r =
    find_regex(s, boost::regex{"\\w\\+\\+"});
  std::cout << r << '\n';
}

Für den regulären Ausdruck wird auf eine Klasse boost::regex zugegriffen, die in der Bibliothek Boost.Regex definiert ist. Boost.Regex wird im Kapitel 8 vorgestellt.

Wenn Sie Beispiel 5.12 ausführen, wird C++ ausgegeben.

Aufgabe

Entwickeln Sie eine Kommandozeilenanwendung, die den Anwender auffordert, seinen vollständigen Namen einzugeben. Die Anwendung soll daraufhin den Anwender mit Hello gefolgt von seinem Namen gefolgt von einem Ausrufezeichen begrüßen. Dabei soll der Vor- und Nachname des Anwenders mit Ausnahme der Anfangsbuchstaben klein geschrieben werden. Außerdem soll der Vor- und Nachname mit genau einem Leerzeichen getrennt werden. Vor dem abschließenden Ausrufezeichen darf kein Leerzeichen stehen.