O gcc 4.8 ou bugs anteriores sobre expressões regulares?

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

#include  #include  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 o gcc (MacPorts gcc47 4.7.1_2) 4.7.1, seja 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 , então parece que o último não é correspondido por alguns motivos. O código funciona bem com o compilador Apple LLVM.

Alguma idéia sobre como resolver o problema?

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

    foi implementado e lançado no GCC 4.9.0.

    Na sua (mais antiga) versão do GCC, ela não está implementada .

    Esse código prototype foi adicionado quando todo o suporte C ++ 0x do GCC era altamente experimental, rastreando rascunhos antigos do C ++ 0x e sendo disponibilizado para as pessoas experimentarem. Isso permitiu que as pessoas encontrassem problemas e dessem feedback ao comitê padrão antes que o padrão fosse finalizado. Na época, muitas pessoas estavam gratas por ter access a resources de ponta antes do C ++ 11 ter sido concluído e antes que muitos outros compiladores fornecessem qualquer suporte, e esse feedback realmente ajudou a melhorar o C ++ 11. Esta foi uma boa coisa TM .

    O código nunca estava em um estado útil, mas foi adicionado como um trabalho em andamento como muitos outros bits de código no momento. Ele foi verificado e disponibilizado para outros colaborarem se quisessem, com a intenção de que terminaria eventualmente.

    Muitas vezes é assim que funciona o código aberto: lançamento antecipado, lançamento frequente – infelizmente, no caso de , apenas acertamos a parte inicial e não a parte que normalmente terminaria a implementação.

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

    Falando sério, porém, quem envia uma implementação de regex_search que apenas “retorna falso” foi uma boa ideia?

    Não foi uma má idéia há alguns anos, quando o C ++ 0x ainda estava em andamento e nós enviamos muitas implementações parciais. Ninguém achou que ficaria inutilizável por tanto tempo, então, em retrospecto, talvez devesse ter sido desativado e requerido uma opção de macro ou de tempo de execução para ativá-lo. Mas esse navio partiu há muito tempo. Existem símbolos exportados do libstdc ++. Assim, a biblioteca que depende do código de regex, então simplesmente removê-lo (em, digamos, o GCC 4.8) não teria sido trivial.

    Detecção de Recurso

    Este é um trecho de código para detectar se a implementação de libstdc++ está implementada com o pré-processador de C define:

     #include  #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 é definido em bits/regex.tcc em 4.9.x
    • _GLIBCXX_REGEX_STATE_LIMIT é definido em bits/regex_automatron.h em 5+
    • _GLIBCXX_RELEASE foi adicionado a 7+ como resultado desta resposta e é a versão principal do GCC

    Testando

    Você pode testá-lo com o GCC assim:

     cat < < EOF | g++ --std=c++11 -x c++ - && ./a.out #include  #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  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 < < " works, look: " < < std::boolalpha << result << std::endl; #else std::cerr << " 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  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  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  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  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  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++'  works, look: true 

    Aqui ser dragões

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

    Se os desenvolvedores do GCC adicionassem um #define _GLIBCXX_HAVE_WORKING_REGEX 1 (ou algo assim, sugestão cutucada cutucada) na versão 7.x que persistisse, esse trecho poderia ser atualizado para include isso e versões posteriores do GCC funcionariam com o trecho acima.

    Tanto quanto eu sei, todos os outros compiladores têm um trabalhando quando __cplusplus >= 201103L mas YMMV.

    Obviamente, isso seria completamente interrompido se alguém definisse as macros _GLIBCXX_REGEX_STATE_LIMIT ou _GLIBCXX_REGEX_STATE_LIMIT fora dos headers stdc++-v3 .

    Neste 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 inVector{ std::sregex_token_iterator(line.begin(), line.end(), re, 1), {} }; //prints all matches for(int i=0; i 

    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