Seit dem Standard C++11 werden reguläre Ausdrücke direkt unterstützt. Wir sehen uns an, wie regex_match in der Praxis verwendet werden kann. Für den Einsatz von regulären Ausdrücken stehen prinzipiell drei Algorithmen zur Verfügung: regex_match, regex_search und regex_replace. Mit den beiden letzten werden wir uns in zukünftigen Artikeln befassen.
Für die Erstellung der Beispiele benötigen wir zuerst die entsprechenden Headerdateien:
1 2 3 |
#include <iostream> //std::cout #include <string> //std::string #include <regex> //std::regex |
Nun können wir in der Hauptroutine mit einem ersten einfachen Beispiel beginnen. Für die Verwendung von regex_match benötigen wir grundsätzlich einen String der durchsucht werden soll, sowie einen regulären Ausdruck, in dem die Grammatik für die Suche definiert ist. In unserem Beispiel überprüfen wir die Syntax eines Benutzernamens einer Dating Webseite. Wir belegen den String search
mit dem Wert "sonnenschein84"
und wollen nun herausfinden, ob der Name dem Ausdruck std::regex reg(R"(([a-z]+)(\d+))")
entspricht. Es werden hier zwei Suchgruppen definiert. Der erste Teil des Namens muss aus einer beliebigen Anzahl von Kleinbuchstaben bestehen, der Zweite aus einer beliebigen Anzahl von Ziffern. Die Verwendung von C++11 erlaubt hier den Einsatz eines Raw Strings (gekennzeichnet durch R
). Bei Verwendung eines herkömmlichen Strings müssten wir vor den Parameter \d+
noch ein zusätzliches Escape Zeichen anhängen.
1 2 3 4 5 6 7 |
// Einfache Verwendung von regex_match std::string search("sonnenschein84"); std::regex reg(R"(([a-z]+)(\d+))"); if (std::regex_match(search, reg)) { std::cout << "String \"" << search << "\" ist gültig." << std::endl; } |
String "sonnenschein84" ist gültig.
Wir stellen fest, dass der Name der definierten Grammatik entspricht. In der Praxis ist es oft notwendig, den Wert und die Position der Teilergebnisse zu kennen. Dies lässt sich mit dem Container std::match_results bewerkstelligen. Für den Typ std::string verwenden wir den Suchtyp smatch
. Diesen übergeben wir nun zusätzlich an regex_match. In einer for Schleife können wir nun auf alle Suchergebnisse zugreifen.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Gesamtergebnis, Teilergebnisse und deren Position anzeigen std::smatch match; if (std::regex_match(search, match, reg)) { for (unsigned int i = 0; i < match.size(); ++i) { std::cout << "Position: " << match.position(i) << " Länge : " << match.length(i) << " - " << match.str(i) << std::endl; } } |
Position: 0 Länge : 14 - sonnenschein84
Position: 0 Länge : 12 - sonnenschein
Position: 12 Länge : 2 - 84
Unser Ergebnis liefert zuerst die Position, die Länge und den Inhalt für das Gesamtergebnisses. Anschließend werden die entsprechenden Werte für die Teilergebnisse ausgegeben.
Es ist natürlich auch möglich, Listen und Vektoren mit einzelnen Zeichen oder Zeichenketten zu durchsuchen. Im nächsten Beispiel legen wir einen String Vektor an und befüllen ihn mit mehreren Benutzernamen. Für die Grammatik unseres regulären Ausdruckes legen wir diesmal fest, dass die Zahl am Ende des Strings nur zwei Ziffern aufweisen darf.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Vector durchsuchen std::vector<std::string> vec {"hansi67", "blume333", "28surfer"}; for (const auto &it : vec) { if (std::regex_match(it, std::regex(R"(([a-z]+)(\d{2}))"))) { std::cout << "String \"" << it << "\" ist gültig." << std::endl; } else { std::cout << "String \"" << it << "\" ist ungültig." << std::endl; } } |
String "hansi67" ist gültig.
String "blume333" ist ungültig.
String "28surfer" ist ungültig.
Im Ergebnis sind die Zeichenketten "blume333"
und "28surfer"
ungültig. Der erste String hat drei Ziffern am Ende – dies ist eine zu viel. Der zweite String beginnt mit einer Ziffer. Dies ist laut unseres regulären Ausdruckes grundsätzlich falsch. Laut unserer Definition muss der Name mit einem Buchstaben beginnen.
Für unser letztes Beispiel definieren wir oberhalb der Hauptroutine zunächst die Funktion void verifyString(std::string str, std::regex expr)
. Wir können nun komfortabel zu durchsuchende Strings direkt an unsere Funktion übergeben. Diese prüft den Inhalt des Strings und kümmert sich auch um die Ausgebe des Ergebnisses. Wir überprüfen zwei Strings bezüglich eines gültigen C++ Standards. Hier bietet sich auch die Gelegenheit, den Einsatz von Optionen zu zeigen. Im ersten Fall weisen wir an, dass die Groß – und Kleinschreibung ignoriert werden soll. Im zweiten Fall wird der reguläre Ausdruck zusätzlich vorkompiliert.
1 2 3 4 5 6 7 8 9 10 11 12 |
// string 'str' überprüfen gemäß regulärem Ausdruck 'expr' void verifyString(std::string str, std::regex expr) { if (std::regex_match(str, expr)) { std::cout << "String \"" << str << "\" ist gültig." << std::endl; } else { std::cout << "String \"" << str << "\" ist ungültig." << std::endl; } } |
1 2 3 4 5 |
// Funktion verwenden und Optionen setzen verifyString("x++17", std::regex(R"((c\++)(98|03|11|14|17))", std::regex_constants::icase)); verifyString("C++14", std::regex(R"((c\++)(98|03|11|14|17))", std::regex_constants::icase | std::regex_constants::optimize)); |
String "x++17" ist ungültig.
String "C++14" ist gültig.
Unser Ergebnis zeigt erwartungsgemäß, dass "x++17"
ein ungültiger C++ Standard ist. Das Große "C"
im zweiten String ist gültig aufgrund der Option std::regex_constants::icase
.
Das Beispiel kann folgendermaßen kompiliert und ausgeführt werden:
g++ -std=c++11 cpp_regex_1.cpp && ./a.out
Das komplette Beispiel herunterladen: cpp_regex_match.zip
Hinterlasse jetzt einen Kommentar