Czy gcc 4.8 lub wcześniejszy błąd dotyczy wyrażeń regularnych?

Próbuję użyć std::regex w części kodu C++11, ale wygląda na to, że obsługa jest trochę błędna. Przykład:

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

Wyjścia:

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

Po skompilowaniu z gcc (MacPorts gcc47 4.7.1_2) 4.7.1, albo z

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

Lub

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

Poza tym regex działa dobrze, jeśli mam tylko dwa alternatywne wzory, np. st|mt, więc wygląda na to, że ostatni nie jest dopasowany z pewnych powodów. Kod działa dobrze z kompilatorem Apple LLVM.

Wszelkie pomysły o tym, jak rozwiązać problem?

Update jednym z możliwych rozwiązań jest użycie grup do zaimplementowania wielu alternatyw, np. (st|mt)|tr.

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

3 answers

<regex> został zaimplementowany i wydany w GCC 4.9.0.

W Twojej (starszej) wersji GCC jest nie zaimplementowana.

Ten prototyp <regex> kod został dodany, gdy cała obsługa C++0x GCC była wysoce eksperymentalna, śledząc wczesne szkice C++0x i udostępniając je ludziom do eksperymentowania. Pozwoliło to ludziom znaleźć problemy i przekazać opinię Komitetowi ds. standardów przed sfinalizowaniem normy. W tym czasie wiele osób było wdzięcznych aby mieć dostęp do funkcji bleeding edge na długo przed ukończeniem C++11 i zanim wiele innych kompilatorów zapewniło jakiekolwiek wsparcie, a te opinie naprawdę pomogły ulepszyć C++11. To była dobra rzeczTM .

Kod <regex> nigdy nie był użyteczny, ale został dodany jako praca w toku, jak wiele innych bitów kodu w tym czasie. Został on sprawdzony i udostępniony innym do współpracy, jeśli chcą, z zamiarem, że zostanie ukończony w końcu.

Tak często działa open source: Release early, release czesto -- niestety w przypadku <regex> mamy tylko poprawną część wczesną, a nie często część, która skończyłaby implementację.

Większość części biblioteki była bardziej kompletna i obecnie jest prawie w pełni zaimplementowana, ale <regex> nie była, więc pozostała w tym samym niedokończonym stanie, odkąd została dodana.

Poważnie choć, kto choć, że wysyłka an implementacja regex_search, która tylko "return false" była dobrym pomysłem?

To nie był taki zły pomysł kilka lat temu, kiedy C++0x był jeszcze w toku i wysłaliśmy wiele częściowych implementacji. Nikt nie sądził, że pozostanie bezużyteczny przez tak długi czas, więc z perspektywy czasu może powinien być wyłączony i wymagał opcji makra lub wbudowanej w czasie, aby go włączyć. Ale ten statek odpłynął dawno temu. Są eksportowane symbole z libstdc++. tak więc biblioteka, która zależy od kodu regex, więc po prostu usunięcie go (np. w GCC 4.8) nie byłoby trywialne.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-28 23:06:12

Wykrywanie Funkcji

Jest to fragment do wykrycia, czy implementacja libstdc++ jest zaimplementowana z preprocesorem C definiuje:

#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

Makra

  • _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT jest zdefiniowane w bits/regex.tcc w 4.9.x
  • _GLIBCXX_REGEX_STATE_LIMIT jest zdefiniowane w bits/regex_automatron.h W 5+
  • _GLIBCXX_RELEASE został dodany do 7+ w wyniku tej odpowiedzi i jest główną wersją gcc

Testowanie

Można go przetestować z GCC jak to:

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

Wyniki

Oto wyniki dla różnych kompilatorów:


$ 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

Here be Dragons

Jest to całkowicie nieobsługiwane i polega na wykrywaniu prywatnych makr, które programiści GCC umieścili w nagłówkach bits/regex*. Mogą się zmienić i odejść o w każdej chwili . Mam nadzieję, że nie zostaną usunięte w obecnej wersji 4.9.x, 5.x, 6.x wypuszcza, ale mogą odejdź w 7.x releases.

Jeśli deweloperzy GCC dodali #define _GLIBCXX_HAVE_WORKING_REGEX 1 (lub coś, podpowiedź podpowiedź nudge nudge) w 7.wersja X, która utrzymywała się, ten fragment może zostać zaktualizowany, aby zawierał ten fragment, a późniejsze wydania GCC będą działać z fragmentem powyżej.

Z tego co wiem, wszystkie inne Kompilatory mają działające <regex> Kiedy __cplusplus >= 201103L ale YMMV.

Oczywiście byłoby to całkowicie złamane, gdyby ktoś zdefiniował makra _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT lub _GLIBCXX_REGEX_STATE_LIMIT poza nagłówkami 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-11 14:42:53

W tej chwili (używanie std = c++14 W g++ (GCC) 4.9.2) nadal nie akceptuje regex_match.

Oto podejście, które działa jak regex_match, ale zamiast tego używa sortex_token_iterator. I działa z 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;

Wydrukuje 1 2 3

Możesz przeczytać referencję sregex_token_iterator w: 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-10 18:32:30