Gcc 4.8 o precedente presenta bug sulle espressioni regolari?


101

Sto cercando di usare std :: regex in un pezzo di codice C ++ 11, ma sembra che il supporto sia un po 'bacato. Un esempio:

#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;
}

uscite:

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

se compilato con gcc (MacPorts gcc47 4.7.1_2) 4.7.1, anche con

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

o

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

Inoltre, la regex funziona bene se ho solo due modelli alternativi, ad esempio st|mt, quindi sembra che l'ultimo non sia abbinato per alcuni motivi. Il codice funziona bene con il compilatore LLVM di Apple.

Qualche idea su come risolvere il problema?

Aggiornare una possibile soluzione è utilizzare i gruppi per implementare più alternative, ad es (st|mt)|tr.


9
Sì, il <regex>supporto di libstdc ++ è incompleto. Cosa possiamo aiutarti?
kennytm

10
Per lo stato di regexin libstdc ++, vedere gcc.gnu.org/onlinedocs/libstdc++/manual/…
ecatmur

51
Seriamente, però, chi ha pensato che spedire un'implementazione di regex_search che "restituisce solo false" fosse una buona idea? "Oh, l'abbiamo documentato" sembra una risposta debole.
Paul Rubel,

4
@ AK4749: questo non è un errore. È semplicemente non implementato. Anche se la quantità di volte in cui questa domanda si presenta è allarmante, soprattutto perché non è cambiato nulla su libstdc ++ <regex>negli ultimi 3-4 anni (come in: rimane non implementato).
rubenvb

5
@KeithThompson, mentre è vero che <regex>è fornito da libstdc ++ (la libreria standard di GCC) non gcc(il front-end del compilatore), fa parte di GCC (il progetto). Vedi "libstdc ++ - v3 è sviluppato e rilasciato come parte di GCC" . Se la tua distribuzione sceglie di dividerla in un pacchetto separato, non ha nulla a che fare con GCC.
Jonathan Wakely

Risposte:


168

<regex> è stato implementato e rilasciato in GCC 4.9.0.

Nella tua versione (precedente) di GCC, non è implementato .

Quel <regex>codice prototipo è stato aggiunto quando tutto il supporto C ++ 0x di GCC era altamente sperimentale, tenendo traccia delle prime bozze C ++ 0x e reso disponibile per le persone con cui sperimentare. Ciò ha permesso alle persone di trovare problemi e fornire feedback al comitato standard prima che lo standard fosse finalizzato. A quel tempo molte persone erano grati di avere accesso dovuto bleeding edge dispone di molto tempo prima che C ++ 11 era finito e prima di molti altri compilatori fornito alcun sostegno, e che il feedback in realtà ha contribuito a migliorare C ++ 11. Questa era una buona cosa TM .

Il <regex>codice non era mai in uno stato utile, ma è stato aggiunto come work-in-progress come molti altri bit di codice in quel momento. È stato archiviato e reso disponibile ad altri per collaborare se lo desiderano, con l'intenzione che alla fine sarebbe finito.

Questo è spesso il modo in cui funziona l'open source: rilascia presto, rilascia spesso - sfortunatamente nel caso di <regex>abbiamo ottenuto solo la prima parte giusta e non la parte spesso che avrebbe terminato l'implementazione.

La maggior parte delle parti della libreria erano più complete e ora sono quasi completamente implementate, ma <regex>non lo erano, quindi è rimasta nello stesso stato incompiuto da quando è stata aggiunta.

Seriamente, però, chi ha pensato che spedire un'implementazione di regex_search che "restituisce solo false" fosse una buona idea?

Non è stata una cattiva idea alcuni anni fa, quando C ++ 0x era ancora un work in progress e abbiamo distribuito molte implementazioni parziali. Nessuno pensava che sarebbe rimasto inutilizzabile per così tanto tempo quindi, con il senno di poi, forse avrebbe dovuto essere disabilitato e richiedere un'opzione macro o built-time per abilitarlo. Ma quella nave ha navigato molto tempo fa. Ci sono simboli esportati da libstdc ++. Quindi librerie che dipendono dal codice regex, quindi rimuoverlo semplicemente (ad esempio in GCC 4.8) non sarebbe stato banale.


12

Rilevamento delle caratteristiche

Questo è uno snippet per rilevare se l' libstdc++implementazione è implementata con il preprocessore C definisce:

#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

Macro

  • _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMITè definito in bits/regex.tccin4.9.x
  • _GLIBCXX_REGEX_STATE_LIMITè definito in bits/regex_automatron.hin5+
  • _GLIBCXX_RELEASEè stato aggiunto 7+come risultato di questa risposta ed è la versione principale di GCC

analisi

Puoi testarlo con GCC in questo modo:

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

risultati

Ecco alcuni risultati per vari compilatori:


$ 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

Ecco i draghi

Questo non è totalmente supportato e si basa sul rilevamento di macro private che gli sviluppatori di GCC hanno inserito nelle bits/regex*intestazioni. Potrebbero cambiare e andarsene in qualsiasi momento . Si spera che non vengano rimossi nelle attuali versioni 4.9.x, 5.x, 6.x ma potrebbero scomparire nelle versioni 7.x.

Se gli sviluppatori di GCC hanno aggiunto un #define _GLIBCXX_HAVE_WORKING_REGEX 1(o qualcosa del genere, suggerimento hint nudge nudge) nella versione 7.x che persisteva, questo frammento potrebbe essere aggiornato per includerlo e le versioni successive di GCC funzionerebbero con lo snippet sopra.

Per quanto ne so, tutti gli altri compilatori hanno un <regex>quando funzionante __cplusplus >= 201103Ltranne YMMV.

Ovviamente questo si interromperebbe completamente se qualcuno definisse le macro _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMITo _GLIBCXX_REGEX_STATE_LIMITal di fuori delle stdc++-v3intestazioni.


Molto bella! Stavo per suggerire di controllare la macro di protezione dell'intestazione da una delle intestazioni che è nuova in GCC 4.9, ma non hanno protezioni: - \ Le macro non cambiano per GCC 7, ma teoricamente potrebbero fare per GCC 8+, quindi per favore invia una richiesta di miglioramento su gcc.gnu.org/bugzilla chiedendo qualcosa come _GLIBCXX_REGEX_IS_OK_NOW_KTHXBAInelle intestazioni, in modo che non venga dimenticato - grazie!
Jonathan Wakely

1
@JonathanWakely hanno aggiunto 78905 . Non sono sicuro di come trasformarlo in un bug di miglioramento, ma ora è nel sistema.
Matt Clarkson

1

In questo momento (usando std = c ++ 14 in g ++ (GCC) 4.9.2) continua a non accettare regex_match.

Ecco un approccio che funziona come regex_match ma utilizza invece sregex_token_iterator. E funziona con 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;

stamperà 1 2 3

puoi leggere il riferimento a sregex_token_iterator in: http://en.cppreference.com/w/cpp/regex/regex_token_iterator


1
"Al momento (utilizzando std = c ++ 14 in g ++ (GCC) 4.9.2) continua a non accettare regex_match." Non è vero, probabilmente lo stai usando in modo sbagliato.
Jonathan Wakely,

1
Il tuo codice non è "un approccio che funziona come regex_match" perché quella funzione cerca di abbinare le sottostringhe, non l'intera stringa, quindi penso ancora che tu lo stia usando in modo sbagliato. Puoi farlo con std::regex_search, però, vedi wandbox.org/permlink/rLbGyYcYGNsBWsaB
Jonathan Wakely,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.