2017-09-01 8 views
0

Die std::regex_match() endet nicht (GCC 5.4.0 20160609, x86_64, Ubuntu 16.04).Std :: Regex Endlosschleife mit gcc 5.4

Aber es funktioniert in einigen der Online-Compiler: http://cpp.sh/ ist in Ordnung, zum Beispiel.

Der Code versucht, eine INI-artige Abschnittsüberschrift mit einem möglichen "#" - Kommentar zu vergleichen.

#include <regex> 

int main(int argc, char *argv[]) 
{ 
    std::regex headerPattern("([[:blank:]]*\\[[[:blank:]]*((?:[[:blank:]]*[^[:space:]]+[[:blank:]]*?)+)[[:blank:]]*\\][[:blank:]]*(?:#(?:[^[:space:]]*[[:blank:]]*)*)?)"); 
    std::smatch headerMatch; 
    std::string l("[Hdr 100] # ------------ 22 22 4444 88888888 333"); 
    return std::regex_match(l, headerMatch, headerPattern) ? 0 : 1; 
} 

Körperbau:

g++ -std=c++11 main.cpp -o main 

Gibt es wirklich ein Problem mit dem Code?

Antwort

1

Das Muster verursacht katastrophale Rückverfolgung. Es passiert, weil Sie eine wiederholte Erfassungsgruppe ((?:[[:blank:]]*[^[:space:]]+[[:blank:]]*?)+) haben (aus Gründen der Einfachheit, lassen Sie es mit PCRE-Syntax wie ((?:\h*\S+\h*?)+) schreiben) und es entspricht 0+ horizontalen Leerzeichen, dann 1 oder mehr Nicht-Leerzeichen Zeichen gefolgt von 0+ horizontalen Leerzeichen, und alle Dies wird mit + quantifiziert. Dies ist ein klassischer (a+)+ Fall innerhalb eines Musters, der das katastrophale Backtracking unvermeidlich macht.

Sie müssen diese und die andere Gruppe die folgende Art und Weise entrollen:

std::regex headerPattern("([[:blank:]]*\\[[[:blank:]]*([^[:space:]]+(?:[[:blank:]]+[^[:space:]]+)*)[[:blank:]]*\\][[:blank:]]*(?:#[^[:space:]]*(?:[[:blank:]]+[^[:space:]]+)*)?)"); 

Siehe regex demo. Und hier ist ein PCRE-converted variant, um den Unterschied zu verstehen: die Gruppe, die ich oben erwähnt habe, ist jetzt \S+(?:\h+\S+)*: 1+ Nicht-Whitespace-Zeichen gefolgt von 0+ Sequenzen von 1+ horizontalen Leerzeichen gefolgt von 1+ Nicht-Leerzeichen Zeichen. Die letzte einfangende Gruppe wird in \S*(?:\h+\S+)* geändert: 0+ Nicht-Leerzeichen-Zeichen gefolgt von 0+ Folgen von 1+ horizontalen Leerzeichenzeichen gefolgt von 1+ Nicht-Leerzeichen-Zeichen.

Ersetzen Sie einfach \h mit [[:blank:]] (oder [^\\S\r\n]) und \S mit [^[:space:]] (oder sie halten, std::regex unterstützt) zurückzukehren, dass PCRE Muster auf das von Ihnen verwendete.

Verwandte Themen