O gcc 4.8 ou anterior apresenta erros em relação às expressões regulares?

101

Estou tentando usar std :: regex em um pedaço de código C ++ 11, mas parece que o suporte é um pouco bugado. Um exemplo:

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

saídas:

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

quando compilado com gcc (MacPorts gcc47 4.7.1_2) 4.7.1, ou com

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

ou

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

Além disso, o regex funciona bem se eu tiver apenas dois padrões alternativos, por exemplo st|mt, parece que o último não é compatível por alguns motivos. O código funciona bem com o compilador LLVM da Apple.

Alguma ideia de como resolver o problema?

Atualizar uma solução possível é usar grupos para implementar alternativas múltiplas, por exemplo (st|mt)|tr.

Tunnuz
fonte
9
Sim, o <regex>suporte do libstdc ++ está incompleto. O que podemos ajudar você?
kennytm
10
Para o status de regexem libstdc ++, consulte gcc.gnu.org/onlinedocs/libstdc++/manual/…
ecatmur
51
Sério, quem achou que enviar uma implementação de regex_search que apenas "retorna falso" era uma boa ideia? "Oh, nós documentamos" parece uma resposta fraca.
Paul Rubel
4
@ AK4749: isso não é um erro. É simplesmente não implementado. Embora a quantidade de vezes que essa pergunta aparece seja alarmante, especialmente porque nada mudou sobre o libstdc ++ <regex>nos últimos 3-4 anos (como em: ele permanece não implementado).
rubenvb
5
@KeithThompson, embora seja verdade que <regex>é fornecido pelo libstdc ++ (a biblioteca padrão do GCC) e não gcc(o front end do compilador), ele faz parte do GCC (o projeto). Consulte "libstdc ++ - v3 é desenvolvido e lançado como parte do GCC" . Se sua distro decidir dividi-lo em um pacote separado, isso não tem nada a ver com o GCC.
Jonathan Wakely,

Respostas:

168

<regex> foi implementado e lançado no GCC 4.9.0.

Em sua versão (mais antiga) do GCC, ele não está implementado .

Esse <regex>código de protótipo foi adicionado quando todo o suporte C ++ 0x do GCC era altamente experimental, rastreando os primeiros rascunhos C ++ 0x e sendo disponibilizado para que as pessoas experimentassem. Isso permitiu que as pessoas encontrassem problemas e dessem feedback ao comitê de padrão antes que o padrão fosse finalizado. Na época, muitas pessoas ficaram gratas por ter acesso a recursos de ponta muito antes da conclusão do C ++ 11 e antes que muitos outros compiladores fornecessem qualquer suporte, e esse feedback realmente ajudou a melhorar o C ++ 11. Este foi um Good Thing TM .

O <regex>código nunca esteve em um estado útil, mas foi adicionado como um trabalho em andamento como muitos outros bits de código da época. Ele foi verificado e disponibilizado para que outras pessoas colaborassem, se quisessem, com a intenção de que acabasse eventualmente.

Freqüentemente, é assim que o código aberto funciona: libere com antecedência, libere com frequência - infelizmente, no caso de <regex>apenas acertarmos a parte inicial e não a parte frequente que teria concluído a implementação.

A maioria das partes da biblioteca estava mais completa e agora está quase totalmente implementada, mas <regex>não estava, então ela permaneceu no mesmo estado inacabado desde que foi adicionada.

Sério, quem achou que enviar uma implementação de regex_search que apenas "retorna falso" era uma boa ideia?

Não era uma ideia tão ruim alguns anos atrás, quando C ++ 0x ainda era um trabalho em andamento e nós distribuímos muitas implementações parciais. Ninguém pensou que permaneceria inutilizável por tanto tempo, então, olhando para trás, talvez devesse ter sido desativado e necessário uma macro ou opção de tempo embutido para ativá-lo. Mas aquele navio navegou há muito tempo. Existem símbolos exportados do libstdc ++. Portanto, a biblioteca que depende do código regex, portanto, simplesmente removê-lo (digamos, no GCC 4.8) não teria sido trivial.

Jonathan Wakely
fonte
12

Detecção de recursos

Este é um snippet para detectar se a libstdc++implementação é implementada com o pré-processador 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é definida em bits/regex.tccnas4.9.x
  • _GLIBCXX_REGEX_STATE_LIMITé definida em bits/regex_automatron.hnas5+
  • _GLIBCXX_RELEASEfoi adicionado 7+como resultado desta resposta e é a versão principal do GCC

Testando

Você pode testá-lo com o GCC desta forma:

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

Aqui estão alguns resultados para vários 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

Aqui estão dragões

Isso é totalmente incompatível e depende da detecção de macros privadas que os desenvolvedores do GCC colocaram nos bits/regex*cabeçalhos. Eles podem mudar e ir embora a qualquer momento . Esperançosamente, eles não serão removidos nas versões 4.9.x, 5.x, 6.x atuais, mas podem desaparecer nas versões 7.x.

Se os desenvolvedores do GCC adicionaram uma #define _GLIBCXX_HAVE_WORKING_REGEX 1(ou algo assim, dica dica nudge nudge) na versão 7.x que persistiu, este snippet poderia ser atualizado para incluir isso e versões posteriores do GCC funcionariam com o snippet acima.

Pelo que eu sei, todos os outros compiladores têm uma função <regex>quando, __cplusplus >= 201103Lexceto YMMV.

Obviamente, isso seria completamente quebrado se alguém definisse as macros _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMITou _GLIBCXX_REGEX_STATE_LIMITfora dos stdc++-v3cabeçalhos.

Matt Clarkson
fonte
Muito agradável! Eu ia sugerir verificar a macro de proteção do cabeçalho de um dos cabeçalhos que é novo no GCC 4.9, mas eles não têm proteções: - \ As macros não estão mudando para o GCC 7, mas teoricamente poderiam fazer para o GCC 8+, então, preencha um pedido de melhoria em gcc.gnu.org/bugzilla pedindo algo como _GLIBCXX_REGEX_IS_OK_NOW_KTHXBAInos cabeçalhos, para que não seja esquecido - obrigado!
Jonathan Wakely
1
@JonathanWakely adicionou 78905 . Não tenho certeza de como transformar isso em um bug de aprimoramento, mas agora está no sistema.
Matt Clarkson
1

No momento (usando std = c ++ 14 em g ++ (GCC) 4.9.2) ainda não está aceitando regex_match.

Aqui está uma abordagem que funciona como regex_match, mas usando sregex_token_iterator. E funciona com 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;

vai imprimir 1 2 3

você pode ler a referência sregex_token_iterator em: http://en.cppreference.com/w/cpp/regex/regex_token_iterator

Luis orantes
fonte
1
"No momento (usando std = c ++ 14 em g ++ (GCC) 4.9.2) ainda não está aceitando regex_match." Isso não é verdade, provavelmente você está usando errado.
Jonathan Wakely
1
Seu código não é "uma abordagem que funciona como regex_match" porque essa função tenta combinar sub-strings, não a string inteira, então ainda acho que você está usando errado. No std::regex_searchentanto, você pode fazer isso com , consulte wandbox.org/permlink/rLbGyYcYGNsBWsaB
Jonathan Wakely