2017-09-06 12 views
3

$ J'essaie d'analyser le contenu du fichier avec une expression régulière:std :: regex ne reconnaît pas

ifstream file_stream("commented.cpp",ifstream::binary); 

std::string txt((std::istreambuf_iterator<char>(file_stream)), 
std::istreambuf_iterator<char>()); 

cmatch m; 
bool result = regex_search(txt.c_str(), m, regex("^#(\S*)$",regex_constants::basic)); 

Le fichier est source de courant alternatif, et il commence par la ligne:

#include <stdio.h> 

J'essaie d'analyser une directive, j'ai vérifié l'expression rationnelle dans regexbuddy et cela fonctionne à 100%, mais dans std :: regex regex_search renvoie false. Il semble que le caractère $ ne soit pas reconnu par gettinc et aussi ^ pour la syntaxe posix. J'ai essayé d'utiliser ECMAScript, et la regex fonctionne, seulement si je supprime $ symbole.

//ecmascript syntax 
bool result = regex_search(txt.c_str(), m, regex("^#(\S*)")); 

Le fichier est lu en utilisant le drapeau binaire, de sorte que la chaîne txt, conserve tous les \r\n caractères qui sont nécessaires pour $ syntaxe. Je cherche de l'aide, comment résoudre ce problème.

+4

Mais '^ # (\ S *) $' '_doesn't_ match de #include '. '\ S' ne correspond qu'aux non-espaces. Il y a des espaces dans '#include ', et vous ne pouvez pas faire correspondre '# include' avec cette regex parce que' $ 'veut s'ancrer à la fin de la ligne. –

Répondre

1

Notez que l'ancre $ fonctionne dans la plupart des cas uniquement comme une ancre de fin de chaîne (entrée entière). Voir this thread. Vous pouvez faire $ correspondre à la fin d'une position de ligne en utilisant un modèle de limite personnalisé basé sur une vue d'ensemble positive, (?=$|\r?\n).

Un autre problème est que vous utilisez \S séquence d'échappement dans un littéral de chaîne régulière. Cela signifie qu'il est traité comme une lettre S, et non comme un motif non-espace. Utilisez un littéral brut de chaîne afin que vous puissiez utiliser un seul \ pour définir une séquence d'échappement regex (où \ s'échappant d, s, etc. doivent être des barres obliques inverses littérales). Ou double évasion \ dans les littéraux de chaîne régulière.

En outre, @HWalters déjà noté que le ^#\S+$ ne correspondra pas #include <stdio.h>, vous devez prendre en compte un espace à l'intérieur. Ainsi, vous pouvez ressembler ^#include[ \t]+(\S+)(?=$|\r?\n), pour vous assurer que vous avez #include, puis des espaces horizontaux, puis capturer un nombre (1 ou plus ici, avec +) de caractères non-espace jusqu'à la fin de la chaîne ou un saut de ligne (CRLF ou LF).

Et voici une snippet:

regex r(R"(^#include[ \t]+(\S+)(?=$|\r?\n))"); 
string s("#include <stdio.h>\r\n#include <regex>"); 
smatch m; 
if (regex_search(s, m, r)) { 
    std::cout << m[1] << std::endl; 
}