Die Boost C++ Bibliotheken

Kapitel 8. Boost.Regex

Boost.Regex ermöglicht es, reguläre Ausdrücke in C++ einzusetzen. Da die Bibliothek seit C++11 Teil der Standardbibliothek ist, sind Sie nicht auf Boost.Regex angewiesen, wenn Sie in einer Entwicklungsumgebung arbeiten, die C++11 unterstützt. Sie können auf die gleichnamigen Klassen und Funktionen im Namensraum std zugreifen, wenn Sie die Headerdatei regex einbinden.

Die wichtigsten Klassen in Boost.Regex sind boost::regex und boost::smatch, die beide in der Headerdatei boost/regex.hpp definiert sind. Während boost::regex verwendet wird, um einen regulären Ausdruck zu definieren, speichert boost::smatch Suchergebnisse.

Im Folgenden lernen Sie die drei Funktionen kennen, die Boost.Regex zur Suche mit regulären Ausdrücken anbietet.

Beispiel 8.1. Strings mit boost::regex_match() vergleichen
#include <boost/regex.hpp>
#include <string>
#include <iostream>

int main()
{
  std::string s = "Boost Libraries";
  boost::regex expr{"\\w+\\s\\w+"};
  std::cout << std::boolalpha << boost::regex_match(s, expr) << '\n';
}

Die Funktion boost::regex_match(), die im Beispiel 8.1 verwendet wird, vergleicht einen String in Gänze mit einem regulären Ausdruck. Die Funktion gibt true zurück, wenn der reguläre Ausdruck auf den gesamten String passt.

Um einen String nach einem regulären Ausdruck zu durchsuchen, verwenden Sie boost::regex_search().

Beispiel 8.2. Strings mit boost::regex_search() durchsuchen
#include <boost/regex.hpp>
#include <string>
#include <iostream>

int main()
{
  std::string s = "Boost Libraries";
  boost::regex expr{"(\\w+)\\s(\\w+)"};
  boost::smatch what;
  if (boost::regex_search(s, what, expr))
  {
    std::cout << what[0] << '\n';
    std::cout << what[1] << "_" << what[2] << '\n';
  }
}

Die Funktion boost::regex_search() erwartet als zusätzlichen Parameter eine Referenz auf ein Objekt vom Typ boost::smatch. In diesem Objekt speichert boost::regex_search() die Ergebnisse. Dabei wird nur nach Gruppierungen gesucht. So werden im Beispiel 8.2 zwei Ergebnisse gespeichert, weil es zwei Gruppierungen im regulären Ausdruck gibt.

Die Klasse boost::smatch, in der Suchergebnisse gespeichert werden, ist ein Container für Elemente vom Typ boost::sub_match. Sie bietet eine ähnliche Schnittstelle wie std::vector. So kann über operator[] auf Elemente vom Typ boost::sub_match zugegriffen werden.

boost::sub_match speichert Iteratoren auf die Positionen in einem String, die einer Gruppierung in einem regulären Ausdruck entsprechen. Da boost::sub_match von std::pair abgeleitet ist, kann über first und second auf die Iteratoren zugegriffen werden, die einen Substring identifizieren. Wie im Beispiel 8.2 zu sehen, muss nicht auf diese Iteratoren zugegriffen werden, um einen Substring auf die Standardausgabe auszugeben. Da der Operator operator<< für boost::sub_match überladen ist, kann ein Substring direkt ausgegeben werden.

Beachten Sie, dass boost::sub_match Iteratoren speichert. Ergebnisse werden nicht kopiert. Sie dürfen daher auf Iteratoren in Objekten vom Typ boost::sub_match nur zugreifen, solange der String, auf den die Iteratoren zeigen, existiert.

Beachten Sie außerdem, dass das erste Element im Container boost::smatch mit dem Index 0 Iteratoren speichert, die auf den String zeigen, der dem gesamten regulären Ausdruck entspricht. Der erste Substring, der der ersten Gruppierung entspricht, wird über den Index 1 angesprochen.

Die dritte Funktion, die Boost.Regex bietet, ist boost::regex_replace().

Beispiel 8.3. Zeichen in Strings mit boost::regex_replace() ersetzen
#include <boost/regex.hpp>
#include <string>
#include <iostream>

int main()
{
  std::string s = " Boost Libraries ";
  boost::regex expr{"\\s"};
  std::string fmt{"_"};
  std::cout << boost::regex_replace(s, expr, fmt) << '\n';
}

Der Funktion boost::regex_replace() muss neben dem zu durchsuchenden String und einem regulären Ausdruck ein Formatierungsstring übergeben werden. Der Formatierungsstring definiert, wie Substrings, die Gruppierungen im regulären Ausdruck entsprechen, ersetzt werden. Wenn der reguläre Ausdruck so wie im Beispiel 8.3 keine Gruppierungen enthält, werden entsprechende Substrings eins zu eins mit dem Formatierungsstring ersetzt. Beispiel 8.3 gibt als Ergebnis _Boost_Libraries_ aus.

Beachten Sie, dass boost::regex_replace() den gesamten String nach einem regulären Ausdruck durchsucht. So werden im Beispiel 8.3 alle drei Leerzeichen durch einen Unterstrich ersetzt.

Beispiel 8.4. Formatierungsstring mit Referenzen auf Gruppierungen
#include <boost/regex.hpp>
#include <string>
#include <iostream>

int main()
{
  std::string s = "Boost Libraries";
  boost::regex expr{"(\\w+)\\s(\\w+)"};
  std::string fmt{"\\2 \\1"};
  std::cout << boost::regex_replace(s, expr, fmt) << '\n';
}

Im Formatierungsstring kann auf Substrings zugegriffen werden, die durch Gruppierungen im regulären Ausdruck zurückgegeben werden. So können wie im Beispiel 8.4 die Positionen der beiden Wörter getauscht werden, so dass als Ergebnis Libraries Boost ausgegeben wird.

Beachten Sie, dass es verschiedene Standards für reguläre Ausdrücke und Formatierungsstrings gibt. Für alle drei vorgestellten Funktionen kann ein weiterer Parameter übergeben werden, mit dem ein bestimmter Standard ausgewählt werden kann. Außerdem kann zum Beispiel angegeben werden, dass Sonderzeichen in einem Formatierungsstring nicht interpretiert werden sollen, sondern der Formatierungsstring komplett den String ersetzen soll, auf den der reguläre Ausdruck zutrifft.

Beispiel 8.5. Flags für Formatierungsstrings angeben
#include <boost/regex.hpp>
#include <string>
#include <iostream>

int main()
{
  std::string s = "Boost Libraries";
  boost::regex expr{"(\\w+)\\s(\\w+)"};
  std::string fmt{"\\2 \\1"};
  std::cout << boost::regex_replace(s, expr, fmt,
    boost::regex_constants::format_literal) << '\n';
}

Im Beispiel 8.5 wird das Flag boost::regex_constants::format_literal als vierter Parameter an boost::regex_replace() übergeben, um die Interpretation der Sonderzeichen im Formatierungsstring zu unterdrücken. Das Beispiel gibt als Ergebnis \2 \1 aus, da der gesamte String, auf den der reguläre Ausdruck zutrifft, mit dem Formatierungsstring ersetzt wird.

Beispiel 8.6. Mit boost::regex_token_iterator über Strings iterieren
#include <boost/regex.hpp>
#include <string>
#include <iostream>

int main()
{
  std::string s = "Boost Libraries";
  boost::regex expr{"\\w+"};
  boost::regex_token_iterator<std::string::iterator> it{s.begin(), s.end(),
    expr};
  boost::regex_token_iterator<std::string::iterator> end;
  while (it != end)
    std::cout << *it++ << '\n';
}

Boost.Regex bietet mit boost::regex_token_iterator eine Klasse an, um mit einem regulären Ausdruck über einen String zu iterieren. So wird im Beispiel 8.6 über die beiden Wörter im String s iteriert. Dazu wird it mit Iteratoren auf s und dem regulären Ausdruck \w+ initialisiert. Über den Standardkonstruktor wird ein Iterator erzeugt, der das Ende einer Iteration markiert.

Beispiel 8.6 gibt Boost und Libraries aus.

Beispiel 8.7. Mit boost::regex_token_iterator auf Gruppierungen zugreifen
#include <boost/regex.hpp>
#include <string>
#include <iostream>

int main()
{
  std::string s = "Boost Libraries";
  boost::regex expr{"(\\w)\\w+"};
  boost::regex_token_iterator<std::string::iterator> it{s.begin(), s.end(),
    expr, 1};
  boost::regex_token_iterator<std::string::iterator> end;
  while (it != end)
    std::cout << *it++ << '\n';
}

Sie können dem Konstruktor von boost::regex_token_iterator als zusätzlichen Parameter eine Zahl übergeben. Ist wie im Beispiel 8.7 1 angegeben, gibt der Iterator die erste Gruppierung im regulären Ausdruck zurück. Da (\w)\w+ als regulärer Ausdruck verwendet wird, gibt Beispiel 8.7 die Initialen B und L aus.

boost::regex_token_iterator erlaubt es, -1 anzugeben. Der reguläre Ausdruck wird dann als Trennzeichen interpretiert. Ein Iterator, der mit -1 initialisiert wurde, gibt das zurück, auf was der reguläre Ausdruck nicht zutrifft.

Beispiel 8.8. Einen regulären Ausdruck mit einem Locale verknüpfen
#include <boost/regex.hpp>
#include <locale>
#include <string>
#include <iostream>

int main()
{
  std::string s = "Boost k\xfct\xfcphaneleri";
  boost::basic_regex<char, boost::cpp_regex_traits<char>> expr;
  expr.imbue(std::locale{"Turkish"});
  expr = "\\w+\\s\\w+";
  std::cout << std::boolalpha << boost::regex_match(s, expr) << '\n';
}

Im Beispiel 8.8 wird ein Locale über imbue() mit expr verknüpft. Dies geschieht, um den regulären Ausdruck auf den String Boost kütüphaneleri anwenden zu können. Es handelt sich dabei um die türkische Übersetzung von Die Boost-Bibliotheken. Sollen die Umlaute im String vom regulären Ausdruck als gültige Buchstaben erkannt werden, muss das Locale gesetzt werden – andernfalls gibt boost::regex_match() false zurück.

Um einen Locale vom Typ std::locale verwenden zu können, muss expr auf einer Regex-Klasse basieren, die mit dem Typ boost::cpp_regex_traits instanziiert ist. Deswegen verwendet Beispiel 8.8 nicht boost::regex, sondern boost::basic_regex<char, boost::cpp_regex_traits<char>>. Über den zweiten Template-Parameter von boost::basic_regex ist es möglich, indirekt den Parameter für imbue() zu definieren. Nur bei boost::cpp_regex_traits kann ein Locale-Objekt vom Typ std::locale an imbue() übergeben werden.

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.

Beachten Sie, dass boost::regex mit einem plattformabhängigen zweiten Parameter definiert ist. Unter Windows ist dies boost::w32_regex_traits. Damit ist es möglich, einen LCID an imbue() zu übergeben. Es handelt sich hierbei um eine Zahl, die unter Windows einen bestimmten Sprach- und Kulturkreis definiert. Wenn Sie plattformabhängigen Code schreiben möchten, müssen Sie wie im Beispiel 8.8 boost::cpp_regex_traits explizit verwenden. Alternativ können Sie das Makro BOOST_REGEX_USE_CPP_LOCALE definieren.