2017-09-01 1 views
0

Le std::regex_match() ne se termine pas (GCC 5.4.0 20160609, x86_64, Ubuntu 16.04).std :: regex boucle infinie avec gcc 5.4

Mais cela fonctionne dans certains compilateurs en ligne: http://cpp.sh/ est ok, par exemple.

Le code tente de faire correspondre un en-tête de section de style INI avec un commentaire "#" possible.

#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; 
} 

Construire:

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

Est-il vraiment un problème avec le code?

Répondre

1

Le motif provoque un retour arrière catastrophique. Cela arrive parce que vous avez un groupe de capture répété ((?:[[:blank:]]*[^[:space:]]+[[:blank:]]*?)+) (pour simplifier, laissez-moi l'écrire en utilisant la syntaxe PCRE comme ((?:\h*\S+\h*?)+)) et il correspond à 0 + espace horizontal, puis 1 ou plusieurs caractères non-espaces, suivi par 0 + espace horizontal, et tout ceci est quantifié avec +. Il s'agit d'un classique (a+)+ à l'intérieur d'un motif qui rend inévitable le retour en arrière catastrophique.

Vous devez déroulez cela et l'autre groupe de la manière suivante:

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

Voir la regex demo. Et voici un PCRE-converted variant pour comprendre la différence: le groupe que j'ai mentionné ci-dessus est maintenant \S+(?:\h+\S+)*: 1+ chars non-espaces, suivis de 0+ séquences de caractères horizontaux 1+ suivis de 1+ caractères non-espaces. Le dernier groupe de capture est changé en \S*(?:\h+\S+)*: 0+ caractères non-espaces suivis de 0+ séquences de caractères horizontaux 1+ suivis de 1+ caractères non-espaces.

Il suffit de remplacer \h avec [[:blank:]] (ou [^\\S\r\n]) et \S avec [^[:space:]] (ou le garder, std::regex inclus) pour revenir à ce modèle PCRE celui que vous avez utilisé.