Est-ce que gcc 4.8 ou version antérieure est boguée à propos des expressions régulières?

101

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

une fois 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, 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 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.

Tunnuz
la source
9
Oui, le <regex>support de libstdc ++ est incomplet. Que pouvons-nous vous aider?
kennytm
10
Pour le statut de regexdans libstdc ++, voir gcc.gnu.org/onlinedocs/libstdc++/manual/…
ecatmur
51
Sérieusement cependant, qui a pensé que l'envoi d'une implémentation de regex_search qui ne "retourne que faux" était une bonne idée? "Oh, nous l'avons documenté" semble être une réponse faible.
Paul Rubel
4
@ AK4749: ce n'est pas une erreur. Ce n'est tout simplement pas mis en œuvre. Bien que le nombre de fois où cette question se présente soit alarmant, d'autant plus que rien n'a changé à propos de libstdc ++ <regex>au cours des 3-4 dernières années (comme dans: il reste non implémenté).
rubenvb
5
@KeithThompson, alors qu'il est vrai que <regex>c'est fourni par libstdc ++ (la bibliothèque standard de GCC) pas gcc(le frontal du compilateur), il fait partie de GCC (le projet). Voir «libstdc ++ - v3 est développé et publié dans le cadre de GCC» . Si votre distribution choisit de la diviser en un package séparé, cela n'a rien à voir avec GCC.
Jonathan Wakely

Réponses:

168

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

Dans votre (ancienne) version de GCC, il n'est pas implémenté .

Ce <regex>code prototype a été ajouté lorsque tout le support C ++ 0x de GCC était hautement expérimental, traçant les premières ébauches de C ++ 0x et étant mis à la disposition des utilisateurs. 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 à des fonctionnalités de pointe bien avant la fin de C ++ 11 et avant que de nombreux autres compilateurs ne fournissent de support, et ces commentaires ont vraiment aidé à améliorer C ++ 11. C'était une bonne chose TM .

Le <regex>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 à l'époque. Il a été enregistré et mis à la disposition des autres pour qu'ils collaborent s'ils le voulaient, avec l'intention qu'il soit fini par la suite.

C'est souvent ainsi que fonctionne l'open source: Libérez tôt, publiez souvent - malheureusement, dans le cas où <regex>nous n'avons eu que la partie initiale 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'ont pas été, donc elle est restée dans le même état inachevé depuis son ajout.

Sérieusement cependant, qui a pensé que l'envoi 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, lorsque C ++ 0x était encore en cours de travail et que nous avons expédié 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 y a des symboles exportés depuis la bibliothèque libstdc ++. Donc, la bibliothèque qui dépend du code regex, donc simplement le supprimer (par exemple dans GCC 4.8) n'aurait pas été trivial.

Jonathan Wakely
la source
12

Détection des fonctionnalités

Ceci est un extrait de code pour détecter si l' libstdc++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_LIMITest définie dans bits/regex.tccau4.9.x
  • _GLIBCXX_REGEX_STATE_LIMITest définie dans bits/regex_automatron.hau5+
  • _GLIBCXX_RELEASEa é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 <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 n'est pas du tout pris en charge et repose sur la détection des macros privées que les développeurs de GCC ont placées dans les en- bits/regex*têtes. Ils pouvaient 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 ajoutaient un #define _GLIBCXX_HAVE_WORKING_REGEX 1(ou quelque chose, un indice) 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 de code ci-dessus.

Autant que je sache, tous les autres compilateurs ont un fonctionnement <regex>quand __cplusplus >= 201103Lmais YMMV.

De toute évidence, cela serait complètement interrompu si quelqu'un définissait les macros _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMITou en _GLIBCXX_REGEX_STATE_LIMITdehors des en- stdc++-v3têtes.

Matt Clarkson
la source
Très agréable! J'allais suggérer de vérifier la macro de garde d'en-tête à partir de l'un des en-têtes qui est nouveau dans GCC 4.9, mais ils n'ont pas de gardes: - \ Les macros ne changent pas pour GCC 7, mais théoriquement, elles pourraient le faire pour GCC 8+, veuillez donc déposer une demande d'amélioration sur gcc.gnu.org/bugzilla demandant quelque chose comme _GLIBCXX_REGEX_IS_OK_NOW_KTHXBAIdans les en-têtes, pour ne pas l'oublier - merci!
Jonathan Wakely
1
@JonathanWakely a ajouté 78905 . Je ne sais pas comment en faire un bogue d'amélioration, mais c'est maintenant dans le système.
Matt Clarkson du
1

Pour le 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 qui utilise à 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 sur: http://en.cppreference.com/w/cpp/regex/regex_token_iterator

Luis Orantes
la source
1
"Pour le moment (utiliser std = c ++ 14 dans g ++ (GCC) 4.9.2) n'accepte toujours pas regex_match." Ce n'est pas vrai, vous l'utilisez probablement mal.
Jonathan Wakely
1
Votre code n'est pas "une approche qui fonctionne comme regex_match" parce que cette fonction essaie de faire correspondre les sous-chaînes, pas la chaîne entière, donc je pense toujours que vous l'utilisez mal. Vous pouvez le faire avec std::regex_search, voir wandbox.org/permlink/rLbGyYcYGNsBWsaB
Jonathan Wakely