web-dev-qa-db-fra.com

Est-ce que gcc 4.8 ou une version antérieure du buggy concerne 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 <regex>
#include <iostream>

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

lors de la compilation 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

En outre, l'expression régulière fonctionne bien si je n'ai que deux modèles alternatifs, par exemple st|mt, il semble donc que le dernier ne corresponde 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?

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

97
tunnuz

<regex> a été implémenté et publié dans GCC 4.9.0.

Dans votre (ancienne) version de GCC, c'est non implémenté .

Ce prototype <regex> du code a été ajouté lorsque toute la prise en charge de C++ 0x par GCC était hautement expérimentale, suivant les premières versions de C++ 0x et étant mise à la disposition des utilisateurs expérimenter avec. Cela a permis aux gens de trouver des problèmes et de donner leur avis au comité de normalisation avant que la norme ne soit finalisée. À l'époque, beaucoup de gens étaient reconnaissants d'avoir eu accès aux fonctionnalités Edge de saignement bien avant la fin de C++ 11 et avant que de nombreux autres compilateurs ne fournissent le support any, et ces commentaires ont vraiment aidé à améliorer C + +11. C'était une bonne choseTM.

Le <regex> le code n'a jamais été dans un état utile, mais a été ajouté en tant que travail en cours comme de nombreux autres morceaux de code à l'époque. Il a été enregistré et mis à la disposition des autres pour qu'ils collaborent s'ils le souhaitent, avec l'intention qu'il soit finalement terminé.

C'est souvent ainsi que fonctionne l'open source: Libérez tôt, libérez souvent - malheureusement dans le cas de <regex> nous n'avons obtenu que la première partie correcte et pas la partie souvent qui aurait terminé 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 <regex> ne l'avait pas été, il est donc resté dans le même état inachevé depuis son ajout.

Sérieusement, qui pensait qu'expédier une implémentation de regex_search qui ne fait que "retourner faux" était une bonne idée?

Ce n'était pas une si mauvaise idée il y a quelques années, lorsque C++ 0x était encore en cours de réalisation et que nous avons livré de nombreuses implémentations partielles. Personne ne pensait qu'il resterait inutilisable aussi longtemps, donc avec le recul, il aurait peut-être dû être désactivé et nécessiter une macro ou une option intégrée pour l'activer. Mais ce navire a navigué il y a longtemps. Il existe des symboles exportés de la bibliothèque libstdc ++. So qui dépendent du code regex, donc le supprimer (dans, disons, GCC 4.8) n'aurait pas été trivial.

161
Jonathan Wakely

Détection des fonctionnalités

Il s'agit d'un extrait de code pour détecter si le libstdc++ l'implémentation est implémentée avec le préprocesseur C définit:

#include <regex>
#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 dans bits/regex_automatron.h dans 5+
  • _GLIBCXX_RELEASE a été ajouté à 7+ à la suite de cette réponse et est la version principale de GCC

Essai

Vous pouvez le tester avec GCC comme ceci:

cat << EOF | g++ --std=c++11 -x c++ - && ./a.out
#include <regex>

#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 <iostream>

int main() {
  const std::regex regex(".*");
  const std::string string = "This should match!";
  const auto result = std::regex_search(string, regex);
#if HAVE_WORKING_REGEX
  std::cerr << "<regex> works, look: " << std::boolalpha << result << std::endl;
#else
  std::cerr << "<regex> 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
<regex> 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
<regex> 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
<regex> 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
<regex> 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
<regex> 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  # compiled with 'clang -lstdc++'
<regex> 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 de GCC ont mises dans le bits/regex* en-têtes. Ils pourraient changer et disparaître à à tout moment . Espérons qu'ils ne seront pas supprimés dans les versions actuelles 4.9.x, 5.x, 6.x mais ils pourraient disparaître dans les versions 7.x.

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

Pour autant que je sache, tous les autres compilateurs ont un <regex> quand __cplusplus >= 201103L mais YMMV.

Évidemment, cela casserait complètement si quelqu'un définissait le _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT ou _GLIBCXX_REGEX_STATE_LIMIT macros en dehors de stdc++-v3 en-têtes.

11
Matt Clarkson

À l'heure actuelle (en utilisant std = c ++ 14 dans g ++ (GCC) 4.9.2), il n'accepte toujours pas regex_match.

Voici une approche qui fonctionne comme regex_match mais en utilisant à la place sregex_token_iterator. Et cela fonctionne avec g ++.

string line="1a2b3c";
std::regex re("(\\d)");
std::vector<std::string> inVector{
    std::sregex_token_iterator(line.begin(), line.end(), re, 1), {}
};

//prints all matches
for(int i=0; i<inVector.size(); ++i)
    std::cout << i << ":" << inVector[i] << endl;

il imprimera 1 2 3

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

0
Luis Orantes