¿Gcc 4.8 o versiones anteriores tienen errores en las expresiones regulares?

101

Estoy tratando de usar std :: regex en un código de C ++ 11, pero parece que el soporte tiene algunos errores. Un ejemplo:

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

salidas:

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

cuando se compila con gcc (MacPorts gcc47 4.7.1_2) 4.7.1, ya sea con

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

o

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

Además, la expresión regular funciona bien si solo tengo dos patrones alternativos, por ejemplo st|mt, por lo que parece que el último no coincide por algunas razones. El código funciona bien con el compilador LLVM de Apple.

¿Alguna idea sobre cómo solucionar el problema?

Actualizar una posible solución es utilizar grupos para implementar múltiples alternativas, por ejemplo (st|mt)|tr.

tunnuz
fuente
9
Sí, el <regex>soporte de libstdc ++ es incompleto. En que te podemos ayudar
kennytm
10
Para conocer el estado de regexlibstdc ++, consulte gcc.gnu.org/onlinedocs/libstdc++/manual/…
ecatmur
51
Sin embargo, en serio, ¿quién pensó que enviar una implementación de regex_search que solo "devuelve falso" fue una buena idea? "Oh, lo documentamos" parece una respuesta débil.
Paul Rubel
4
@ AK4749: esto no es un error. Simplemente no ha sido implementado. Aunque la cantidad de veces que aparece esta pregunta es alarmante, especialmente porque nada cambió en libstdc ++ <regex>en los últimos 3-4 años (como en: permanece sin implementar).
rubenvb
5
@KeithThompson, si bien es cierto que <regex>lo proporciona libstdc ++ (la biblioteca estándar de GCC) y no gcc(la interfaz del compilador), es parte de GCC (el proyecto). Consulte "libstdc ++ - v3 se ha desarrollado y lanzado como parte de GCC" . Si su distribución elige dividirlo en un paquete separado, eso no tiene nada que ver con GCC.
Jonathan Wakely

Respuestas:

168

<regex> fue implementado y lanzado en GCC 4.9.0.

En su versión (anterior) de GCC, no está implementado .

Ese <regex>código prototipo se agregó cuando todo el soporte de C ++ 0x de GCC era altamente experimental, rastreaba los primeros borradores de C ++ 0x y estaba disponible para que las personas experimentaran. Eso permitió a la gente encontrar problemas y dar retroalimentación al comité de estándares antes de que se finalizara el estándar. En el momento muchas personas estaban agradecidos de tener acceso a tenido borde de la sangría cuenta mucho antes de C ++ 11 fue terminado y antes de que muchos otros compiladores proporcionan ningún apoyo, y que realmente ayudó a mejorar la retroalimentación C ++ 11. Esto fue algo bueno TM .

El <regex>código nunca estuvo en un estado útil, pero se agregó como un trabajo en progreso como muchos otros bits de código en ese momento. Se registró y se puso a disposición de otros para que colaboraran si así lo deseaban, con la intención de que finalmente se terminara.

A menudo, así es como funciona el código abierto: lanzamiento temprano, lanzamiento frecuente ; desafortunadamente, en el caso de <regex>que solo hicimos bien la parte inicial y no la parte frecuente que habría terminado la implementación.

La mayoría de las partes de la biblioteca estaban más completas y ahora están casi completamente implementadas, pero <regex>no lo habían sido, por lo que permaneció en el mismo estado sin terminar desde que se agregó.

Sin embargo, en serio, ¿quién pensó que enviar una implementación de regex_search que solo "devuelve falso" fue una buena idea?

No fue tan mala idea hace unos años, cuando C ++ 0x todavía era un trabajo en progreso y enviamos muchas implementaciones parciales. Nadie pensó que permanecería inutilizable durante tanto tiempo, así que, en retrospectiva, tal vez debería haberse deshabilitado y requerir una macro o una opción de tiempo de compilación para habilitarlo. Pero ese barco zarpó hace mucho tiempo. Hay símbolos exportados de libstdc ++. Así que la biblioteca depende del código de expresiones regulares, por lo que simplemente eliminarlo (en, digamos, GCC 4.8) no habría sido trivial.

Jonathan Wakely
fuente
12

Detección de características

Este es un fragmento para detectar si la libstdc++implementación se implementa con el preprocesador C define:

#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_LIMITse define en bits/regex.tccen4.9.x
  • _GLIBCXX_REGEX_STATE_LIMITse define en bits/regex_automatron.hen5+
  • _GLIBCXX_RELEASEse agregó 7+como resultado de esta respuesta y es la versión principal de GCC

Pruebas

Puedes probarlo con GCC así:

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

Resultados

A continuación se muestran algunos resultados de varios compiladores:


$ 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

Aquí hay dragones

Esto es totalmente incompatible y se basa en la detección de macros privadas que los desarrolladores de GCC han colocado en los bits/regex*encabezados. Podían cambiar y desaparecer en cualquier momento . Con suerte, no se eliminarán en las versiones actuales 4.9.x, 5.x, 6.x, pero podrían desaparecer en las versiones 7.x.

Si los desarrolladores de GCC agregaron un #define _GLIBCXX_HAVE_WORKING_REGEX 1(o algo, una sugerencia, una sugerencia, un empujón) en la versión 7.x que persistió, este fragmento podría actualizarse para incluirlo y las versiones posteriores de GCC funcionarían con el fragmento anterior.

Por lo que yo sé, todos los otros compiladores tienen un trabajo <regex>cuando __cplusplus >= 201103L, pero tu caso es distinto.

Obviamente, esto se rompería por completo si alguien definiera las macros _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMITo _GLIBCXX_REGEX_STATE_LIMITfuera de los stdc++-v3encabezados.

Matt Clarkson
fuente
¡Muy agradable! Iba a sugerir verificar la macro de protección de encabezado de uno de los encabezados que es nuevo en GCC 4.9, pero no tienen guardias: - \ Las macros no están cambiando para GCC 7, pero teóricamente podrían hacerlo para GCC 8+, así que presente una solicitud de mejora en gcc.gnu.org/bugzilla solicitando algo como _GLIBCXX_REGEX_IS_OK_NOW_KTHXBAIen los encabezados, para que no se olvide, ¡gracias!
Jonathan Wakely
1
@JonathanWakely ha agregado 78905 . No estoy seguro de cómo convertir eso en un error de mejora, pero ahora está en el sistema.
Matt Clarkson
1

En este momento (usando std = c ++ 14 en g ++ (GCC) 4.9.2) todavía no acepta regex_match.

Aquí hay un enfoque que funciona como regex_match pero usando sregex_token_iterator en su lugar. Y funciona 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;

imprimirá 1 2 3

puede leer la referencia sregex_token_iterator en: http://en.cppreference.com/w/cpp/regex/regex_token_iterator

Luis Orantes
fuente
1
"En este momento (usando std = c ++ 14 en g ++ (GCC) 4.9.2) todavía no se acepta regex_match". Eso no es cierto, probablemente lo estés usando mal.
Jonathan Wakely
1
Su código no es "un enfoque que funciona como regex_match" porque esa función intenta hacer coincidir las subcadenas, no la cadena completa, por lo que todavía creo que lo está usando mal. Sin std::regex_searchembargo, puede hacerlo con , consulte wandbox.org/permlink/rLbGyYcYGNsBWsaB
Jonathan Wakely