¿Es gcc 4.8 o anterior un error sobre las expresiones regulares?


Estoy tratando de usar std::regex en una pieza de código de C++11, pero parece que el soporte es un poco defectuoso. 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.

Cualquier idea acerca de cómo resolver el problema?

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

Author: T.C., 2012-09-21

3 answers

<regex> fue implementado y lanzado en GCC 4.9.0.

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

Ese código prototipo <regex> se agregó cuando todo el soporte de C++0x de GCC era altamente experimental, rastreando los primeros borradores de C++0x y estando disponible para que la gente experimentara con ellos. Eso permitió a las personas encontrar problemas y dar retroalimentación al comité de estándares antes de que el estándar fuera finalizado. En ese momento mucha gente estaba agradecida haber tenido acceso a características de vanguardia mucho antes de que se terminara C++11 y antes de que muchos otros compiladores proporcionaran cualquier soporte, y esa retroalimentación realmente ayudó a mejorar C++11. Esto fue Algo Bueno TM .

El código <regex> nunca estuvo en un estado útil, sino que se agregó como un trabajo en progreso como muchos otros bits de código en ese momento. Fue revisado y hecho disponible para que otras personas a colaborar en si querían, con la intención de que sería terminado finalmente.

Así es a menudo como funciona el código abierto: Release early, release often unfortunately desafortunadamente en el caso de <regex> solo obtuvimos la parte inicial correcta y no la parte a menudo que habría terminado la implementación.

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

En serio, sin embargo, que a pesar de que el envío de un la implementación de regex_search que solo "devuelve false" fue una buena idea?

No fue una 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, por lo que, en retrospectiva, tal vez debería haber sido desactivado y requirió una macro o una opción de tiempo construido para habilitarlo. Pero ese barco zarpó hace mucho tiempo. Hay símbolos exportados desde el libstdc++. así que biblioteca que depende del código regex, así que simplemente eliminarlo (por ejemplo, en GCC 4.8) no habría sido trivial.

 159
Author: Jonathan Wakely,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-28 23:06:12

Detección de características

Este es un fragmento de código para detectar si la implementación libstdc++ 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_LIMIT se define en bits/regex.tcc en 4.9.x
  • _GLIBCXX_REGEX_STATE_LIMIT se define en bits/regex_automatron.h en 5+
  • _GLIBCXX_RELEASE se agregó a 7+ como resultado de esta respuesta y es la versión principal del CCG

Pruebas

Puedes probarlo con GCC como esto:

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

Aquí hay algunos resultados para 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í están los Dragones

Esto no es compatible y se basa en la detección de macros privadas que los desarrolladores de GCC han puesto en las cabeceras bits/regex*. Podrían cambiar y desaparecer en en cualquier momento. Con suerte, no se eliminarán en el actual 4.9.x, 5.x, 6.x releases but they could desaparece en el 7.x releases.

Si los desarrolladores de GCC agregaron un #define _GLIBCXX_HAVE_WORKING_REGEX 1 (o algo así, hint hint nudge nudge) en el 7.x release that persisted, este fragmento podría actualizarse para incluirlo y versiones posteriores de GCC funcionarían con el fragmento anterior.

Hasta donde yo sé, todos los demás compiladores tienen un <regex> cuando __cplusplus >= 201103L pero YMMV.

Obviamente esto se rompería completamente si alguien definiera las macros _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT o _GLIBCXX_REGEX_STATE_LIMIT fuera de las cabeceras stdc++-v3.

 9
Author: Matt Clarkson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-11 14:42:53

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;

Se imprimirá 1 2 3

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

 0
Author: Luis Orantes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-10 18:32:30