Est-ce que gcc 4.8 ou version antérieure bogue sur les expressions régulières?

J’essaie d’utiliser std :: regex dans un morceau de code C ++ 11, mais il semble que le support soit un peu bogué. Un exemple:

#include  #include  int main (int argc, const char * argv[]) { std::regex r("st|mt|tr"); std::cerr << "st|mt|tr" << " matches st? " << std::regex_match("st", r) << std::endl; std::cerr << "st|mt|tr" << " matches mt? " << std::regex_match("mt", r) << std::endl; std::cerr << "st|mt|tr" << " matches tr? " << std::regex_match("tr", r) << std::endl; } 

les sorties:

 st|mt|tr matches st? 1 st|mt|tr matches mt? 1 st|mt|tr matches tr? 0 

quand compilé avec gcc (MacPorts gcc47 4.7.1_2) 4.7.1, soit avec

 g++ *.cc -o test -std=c++11 g++ *.cc -o test -std=c++0x 

ou

 g++ *.cc -o test -std=gnu++0x 

De plus, le regex fonctionne bien si je n’ai que deux motifs alternatifs, par exemple st|mt , de sorte qu’il semble que le dernier ne correspond pas pour certaines raisons. Le code fonctionne bien avec le compilateur Apple LLVM.

Des idées sur la façon de résoudre le problème?

Mettre à jour une solution possible consiste à utiliser des groupes pour implémenter plusieurs alternatives, par exemple (st|mt)|tr .

été implémenté et publié dans GCC 4.9.0.

Dans votre version (antérieure) de GCC, elle n’est pas implémentée .

Ce prototype de code été ajouté lorsque toute la prise en charge C ++ 0x de GCC était hautement expérimentale, en suivant les premiers brouillons C ++ 0x et en les mettant à la disposition des utilisateurs. Cela a permis aux gens de trouver des problèmes et de donner leur avis au comité des normes avant que la norme ne soit finalisée. À ce moment-là, beaucoup de personnes étaient reconnaissantes d’avoir eu access à des fonctionnalités avancées avant la fin de C ++ 11 et avant que de nombreux autres compilateurs ne fournissent un support, et que ces retours consortingbuaient vraiment à améliorer C ++ 11. C’était une bonne chose TM .

Le code n’a jamais été dans un état utile, mais a été ajouté en tant que travail en cours, comme beaucoup d’autres bits de code à la fois. Il a été archivé et mis à la disposition des autres pour qu’ils collaborent s’ils le souhaitaient, avec l’intention de le terminer éventuellement.

C’est souvent ainsi que fonctionne l’open source: lancement anticipé, publication fréquente – malheureusement dans le cas de nous n’avons obtenu que la première partie et non la partie qui aurait fini l’implémentation.

La plupart des parties de la bibliothèque étaient plus complètes et sont maintenant presque entièrement implémentées, mais n’avait pas existé, donc elle est restée dans le même état inachevé depuis son ajout.

Sérieusement, qui, bien que la livraison d’une implémentation de regex_search qui ne “retourne que faux” était une bonne idée?

Ce n’était pas une si mauvaise idée il y a quelques années, quand C ++ 0x était encore en développement et que nous avions livré de nombreuses implémentations partielles. Personne ne pensait que cela restrait inutilisable aussi longtemps, avec le recul, peut-être aurait-il dû être désactivé et nécessiter une macro ou une option intégrée pour l’activer. Mais ce bateau a navigué depuis longtemps. Il y a des symboles exportés de la bibliothèque libstdc ++. So qui dépendent du code regex, donc la simple suppression (par exemple, GCC 4.8) n’aurait pas été sortingviale.

Détection de caractéristiques

Ceci est un extrait pour détecter si l’implémentation de libstdc++ est implémentée avec le préprocesseur C qui définit:

 #include  #if __cplusplus >= 201103L && \ (!defined(__GLIBCXX__) || (__cplusplus >= 201402L) || \ (defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || \ defined(_GLIBCXX_REGEX_STATE_LIMIT) || \ (defined(_GLIBCXX_RELEASE) && \ _GLIBCXX_RELEASE > 4))) #define HAVE_WORKING_REGEX 1 #else #define HAVE_WORKING_REGEX 0 #endif 

Macros

  • _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT est défini dans bits/regex.tcc dans 4.9.x
  • _GLIBCXX_REGEX_STATE_LIMIT est défini en bits/regex_automatron.h dans 5+
  • _GLIBCXX_RELEASE été ajouté à 7+ à la suite de cette réponse et est la version majeure de GCC

Essai

Vous pouvez le tester avec GCC comme ceci:

 cat << EOF | g++ --std=c++11 -x c++ - && ./a.out #include  #if __cplusplus >= 201103L && \ (!defined(__GLIBCXX__) || (__cplusplus >= 201402L) || \ (defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || \ defined(_GLIBCXX_REGEX_STATE_LIMIT) || \ (defined(_GLIBCXX_RELEASE) && \ _GLIBCXX_RELEASE > 4))) #define HAVE_WORKING_REGEX 1 #else #define HAVE_WORKING_REGEX 0 #endif #include  int main() { const std::regex regex(".*"); const std::ssortingng ssortingng = "This should match!"; const auto result = std::regex_search(ssortingng, regex); #if HAVE_WORKING_REGEX std::cerr << " works, look: " << std::boolalpha << result << std::endl; #else std::cerr << " doesn't work, look: " << std::boolalpha << result << std::endl; #endif return result ? EXIT_SUCCESS : EXIT_FAILURE; } EOF 

Résultats

Voici quelques résultats pour différents compilateurs:


 $ gcc --version gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-11) Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ ./a.out  doesn't work, look: false 

 $ gcc --version gcc (GCC) 6.2.1 20160830 Copyright (C) 2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ ./a.out  works, look: true 

 $ gcc --version gcc (Debian 4.9.2-10) 4.9.2 Copyright (C) 2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ ./a.out  works, look: true 

 $ gcc --version gcc (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005 Copyright (C) 2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ ./a.out  works, look: true 

 $ gcc --version gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609 Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ ./a.out  works, look: true 

 $ gcc --version gcc (GCC) 6.2.1 20160830 Copyright (C) 2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ clang --version clang version 3.9.0 (tags/RELEASE_390/final) Target: x86_64-unknown-linux-gnu Thread model: posix InstalledDir: /usr/bin $ ./a.out # comstackd with 'clang -lstdc++'  works, look: true 

Voilà des dragons

Ceci est totalement non pris en charge et repose sur la détection de macros privées que les développeurs GCC ont placées dans les en-têtes bits/regex* . Ils pourraient changer et partir à tout moment . Heureusement, ils ne seront pas supprimés dans les versions 4.9.x, 5.x, 6.x actuelles, mais ils pourraient disparaître dans les versions 7.x.

Si les développeurs GCC ont ajouté un #define _GLIBCXX_HAVE_WORKING_REGEX 1 (ou quelque chose, indice indice nudge nudge) dans la version 7.x qui persistait, cet extrait de code pourrait être mis à jour pour inclure cela et les versions ultérieures de GCC fonctionneraient avec l'extrait ci-dessus.

Autant que je sache, tous les autres compilateurs ont un lorsque __cplusplus >= 201103L mais YMMV.

Évidemment, cela se briserait complètement si quelqu'un définissait les macros _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT ou _GLIBCXX_REGEX_STATE_LIMIT dehors des en- stdc++-v3 .

En ce moment (utiliser std = c ++ 14 dans g ++ (GCC) 4.9.2) n’accepte toujours pas regex_match.

Voici une approche qui fonctionne comme regex_match mais utilise plutôt sregex_token_iterator. Et ça marche avec g ++.

 ssortingng line="1a2b3c"; std::regex re("(\\d)"); std::vector inVector{ std::sregex_token_iterator(line.begin(), line.end(), re, 1), {} }; //prints all matches for(int i=0; i 

il imprimera 1 2 3

vous pouvez lire la référence sregex_token_iterator dans: http://fr.cppreference.com/w/cpp/regex/regex_token_iterator