105 votes

Est-ce que gcc 4.8 ou antérieur est bogué 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 <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;
}

sorties :

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

lorsqu'il est 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, la regex fonctionne bien si je n'ai que deux motifs alternatifs, par exemple st|mt Il semble donc que le dernier ne corresponde pas pour certaines raisons. Le code fonctionne bien avec le compilateur LLVM d'Apple.

Avez-vous des idées sur la façon de résoudre ce problème ?

Mise à jour une solution possible consiste à utiliser des groupes pour mettre en œuvre des alternatives multiples, par exemple (st|mt)|tr .

175voto

Jonathan Wakely Points 45593

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

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

Ce prototype <regex> Le code a été ajouté lorsque le support C++0x de GCC a été supprimé. hautement expérimentale, qui suit les premières ébauches de C++0x et qui est mise à la disposition des gens pour qu'ils puissent l'expérimenter. Cela a permis aux gens de trouver des problèmes et de donner un retour au comité de normalisation avant que la norme ne soit finalisée. À l'époque, de nombreuses personnes étaient reconnaissantes d'avoir eu accès à des fonctionnalités de pointe bien avant que C++11 ne soit terminé et avant que de nombreux autres compilateurs ne fournissent des fonctionnalités de pointe. tout et ce retour d'information a réellement contribué à améliorer C++11. C'était une bonne chose TM .

En <regex> n'a jamais été dans un état utile, mais a été ajouté comme un travail en cours comme beaucoup d'autres morceaux de code à l'époque. Il a été enregistré et mis à la disposition des autres pour qu'ils puissent y collaborer s'ils le souhaitaient, avec l'intention de le terminer un jour.

C'est souvent ainsi que fonctionne l'open source : Publier tôt, publier souvent -- malheureusement dans le cas de <regex> nous n'avons réussi que la première partie et non la partie la plus importante qui aurait permis de terminer la mise en œuvre.

La plupart des parties de la bibliothèque étaient plus complètes et sont maintenant presque entièrement mises en œuvre, mais <regex> ne l'avait pas été, il est donc resté dans le même état inachevé depuis son ajout.

Sérieusement, qui a pensé que fournir une implémentation de regex_search qui ne fait que "return false" é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 d'élaboration et que nous livrions de nombreuses implémentations partielles. Personne ne pensait qu'elle resterait inutilisable pendant si longtemps et, avec le recul, peut-être aurait-elle dû être désactivée et nécessiter une macro ou une option de construction pour l'activer. Mais cette option a été abandonnée depuis longtemps. Il existe des symboles exportés de la libstdc++.so qui dépendent du code regex, donc le supprimer simplement (dans, disons, GCC 4.8) n'aurait pas été trivial.

14voto

Matt Clarkson Points 2876

Détection des caractéristiques

Il s'agit d'un extrait permettant de détecter si l'option libstdc++ est implémentée avec les définitions du préprocesseur C :

#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 es défini en bits/regex.tcc en 4.9.x
  • _GLIBCXX_REGEX_STATE_LIMIT es défini en bits/regex_automatron.h en 5+
  • _GLIBCXX_RELEASE a été ajouté à 7+ à la suite de cette réponse et est la version majeure de GCC

Essais

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

Ici les Dragons

Cette méthode n'est absolument pas supportée et repose sur la détection de macros privées que les développeurs de GCC ont placées dans le fichier bits/regex* Les en-têtes. Ils peuvent changer et disparaître à à tout moment . Avec un peu de chance, 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é, ce snippet pourrait être mis à jour pour l'inclure et les versions ultérieures de GCC fonctionneraient avec le snippet ci-dessus.

Pour autant que je sache, tous les autres compilateurs disposent d'une fonctionnalité <regex> quand __cplusplus >= 201103L mais YMMV.

Évidemment, cela serait complètement cassé si quelqu'un définissait le _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT o _GLIBCXX_REGEX_STATE_LIMIT en dehors de l'élément stdc++-v3 les en-têtes.

0voto

Luis Orantes Points 105

Pour le moment (en utilisant std=c++14 dans g++ (GCC) 4.9.2), il n'accepte toujours pas les regex_match.

Voici une approche qui fonctionne comme regex_match mais en utilisant sregex_token_iterator à la place. Et elle 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X