Ist gcc 4.8 oder früher fehlerhaft in Bezug auf reguläre Ausdrücke?

101

Ich versuche, std :: regex in einem C ++ 11-Code zu verwenden, aber es scheint, dass die Unterstützung etwas fehlerhaft ist. Ein Beispiel:

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

Ausgänge:

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

beim Kompilieren mit gcc (MacPorts gcc47 4.7.1_2) 4.7.1, entweder mit

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

oder

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

Außerdem funktioniert der Regex gut, wenn ich nur zwei alternative Muster habe, z. B. st|mtsieht es so aus, als ob das letzte aus bestimmten Gründen nicht übereinstimmt. Der Code funktioniert gut mit dem Apple LLVM-Compiler.

Irgendwelche Ideen zur Lösung des Problems?

Aktualisieren Sie eine mögliche Lösung, indem Sie Gruppen verwenden, um mehrere Alternativen zu implementieren, z (st|mt)|tr.

tunnuz
quelle
9
Ja, die <regex>Unterstützung von libstdc ++ ist unvollständig. Was können wir Ihnen helfen?
Kennytm
10
Den Status von regexin libstdc ++ finden Sie unter gcc.gnu.org/onlinedocs/libstdc++/manual/…
ecatmur
51
Im Ernst, wer, obwohl der Versand einer Implementierung von regex_search, die nur "false zurückgibt", eine gute Idee war? "Oh, wir haben es dokumentiert" scheint eine schwache Antwort zu sein.
Paul Rubel
4
@ AK4749: Dies ist kein Fehler. Es ist einfach völlig nicht implementiert. Obwohl die Häufigkeit, mit der diese Frage auftaucht, alarmierend ist, zumal sich <regex>in den letzten drei bis vier Jahren nichts an libstdc ++ geändert hat (wie in: es bleibt nicht implementiert).
Rubenvb
5
@KeithThompson, obwohl es wahr ist, dass <regex>libstdc ++ (die GCC-Standardbibliothek) nicht gcc(das Compiler-Frontend) bereitstellt , ist es Teil von GCC (dem Projekt). Siehe "libstdc ++ - v3 wird als Teil von GCC entwickelt und veröffentlicht" . Wenn Ihre Distribution es in ein separates Paket aufteilt, hat das nichts mit GCC zu tun.
Jonathan Wakely

Antworten:

168

<regex> wurde in GCC 4.9.0 implementiert und veröffentlicht.

In Ihrer (älteren) Version von GCC ist es nicht implementiert .

Dieser Prototypcode <regex>wurde hinzugefügt, als die gesamte C ++ 0x-Unterstützung von GCC sehr experimentell war, frühe C ++ 0x-Entwürfe verfolgte und den Menschen zum Experimentieren zur Verfügung gestellt wurde. Dies ermöglichte es den Menschen, Probleme zu finden und dem Standardkomitee Feedback zu geben, bevor der Standard fertiggestellt wurde. Zu der Zeit , viele Leute waren dankbar , hatte Zugang zu Kante haben Blutungen kennzeichnet lange vor C ++ 11 fertig war und vor vielen anderen Compilern zur Verfügung gestellt jede Unterstützung, und das Feedback wirklich geholfen zu verbessern C ++ 11. Dies war eine gute Sache TM .

Der <regex>Code befand sich nie in einem nützlichen Zustand, sondern wurde wie viele andere Codebits zu dieser Zeit als Work-in-Progress hinzugefügt. Es wurde eingecheckt und anderen zur Zusammenarbeit zur Verfügung gestellt, wenn sie wollten, mit der Absicht, dass es irgendwann fertig sein würde.

So funktioniert Open Source oft: Frühes Release, oftes Release - leider haben <regex>wir nur den frühen Teil richtig gemacht und nicht den oft Teil, der die Implementierung abgeschlossen hätte.

Die meisten Teile der Bibliothek waren vollständiger und sind jetzt fast vollständig implementiert, waren es aber <regex>nicht. Daher blieb sie seit dem Hinzufügen im gleichen unfertigen Zustand.

Im Ernst, wer, obwohl der Versand einer Implementierung von regex_search, die nur "false zurückgibt", eine gute Idee war?

Es war vor ein paar Jahren keine so schlechte Idee, als C ++ 0x noch in Arbeit war und wir viele Teilimplementierungen ausgeliefert haben. Niemand dachte, dass es so lange unbrauchbar bleiben würde, so dass es im Nachhinein vielleicht deaktiviert sein sollte und ein Makro oder eine integrierte Option benötigt, um es zu aktivieren. Aber dieses Schiff ist schon lange gesegelt. Es gibt exportierte Symbole aus libstdc ++. Eine Bibliothek, die vom Regex-Code abhängt. Ein einfaches Entfernen (z. B. in GCC 4.8) wäre also nicht trivial gewesen.

Jonathan Wakely
quelle
12

Funktionserkennung

Dies ist ein Ausschnitt, um festzustellen, ob die libstdc++Implementierung mit C-Präprozessor-Definitionen implementiert ist:

#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

Makros

  • _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMITist definiert in bits/regex.tccin4.9.x
  • _GLIBCXX_REGEX_STATE_LIMITist definiert in bits/regex_automatron.hin5+
  • _GLIBCXX_RELEASEwurde 7+als Ergebnis dieser Antwort hinzugefügt und ist die GCC-Hauptversion

Testen

Sie können es mit GCC folgendermaßen testen:

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

Ergebnisse

Hier sind einige Ergebnisse für verschiedene Compiler:


$ 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

Hier sind Drachen

Dies wird nicht unterstützt und beruht auf der Erkennung privater Makros, die die GCC-Entwickler in die bits/regex*Header eingefügt haben. Sie konnten sich jederzeit ändern und weggehen . Hoffentlich werden sie in den aktuellen Versionen 4.9.x, 5.x, 6.x nicht entfernt, aber sie könnten in den Versionen 7.x verschwinden.

Wenn die GCC-Entwickler #define _GLIBCXX_HAVE_WORKING_REGEX 1in der Version 7.x einen (oder etwas, Hinweis-Hinweis-Anstoß) hinzufügen , der weiterhin besteht, könnte dieses Snippet aktualisiert werden, um dies einzuschließen, und spätere GCC-Versionen würden mit dem obigen Snippet funktionieren.

Soweit ich weiß, haben alle anderen Compilern eine Arbeits <regex>wenn __cplusplus >= 201103Laber YMMV.

Offensichtlich würde dies völlig kaputt gehen, wenn jemand die _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIToder _GLIBCXX_REGEX_STATE_LIMITMakros außerhalb der stdc++-v3Header definiert.

Matt Clarkson
quelle
Sehr schön! Ich wollte vorschlagen, in einem der in GCC 4.9 neuen Header nach dem Header-Guard-Makro zu suchen, aber sie haben keine Guards: - \ Die Makros ändern sich nicht für GCC 7, aber theoretisch könnten sie für GCC funktionieren 8+, also bitte eine Erweiterungsanfrage unter gcc.gnu.org/bugzilla einreichen und nach etwas wie _GLIBCXX_REGEX_IS_OK_NOW_KTHXBAIin den Headern fragen , damit es nicht vergessen wird - danke!
Jonathan Wakely
1
@ JonathanWakely haben 78905 hinzugefügt . Ich bin nicht sicher, wie ich daraus einen Erweiterungsfehler machen soll, aber es ist jetzt im System.
Matt Clarkson
1

Derzeit (unter Verwendung von std = c ++ 14 in g ++ (GCC) 4.9.2) wird regex_match noch nicht akzeptiert.

Hier ist ein Ansatz, der wie regex_match funktioniert, aber stattdessen sregex_token_iterator verwendet. Und es funktioniert mit 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;

es wird 1 2 3 gedruckt

Sie können die Referenz zu sregex_token_iterator unter folgender Adresse lesen: http://en.cppreference.com/w/cpp/regex/regex_token_iterator

Luis Orantes
quelle
1
"Derzeit (unter Verwendung von std = c ++ 14 in g ++ (GCC) 4.9.2) wird regex_match noch nicht akzeptiert." Das ist nicht wahr, Sie verwenden es wahrscheinlich falsch.
Jonathan Wakely
1
Ihr Code ist kein "Ansatz, der wie regex_match funktioniert", da diese Funktion versucht, Teilzeichenfolgen abzugleichen, nicht die gesamte Zeichenfolge. Ich denke also immer noch, dass Sie ihn falsch verwenden. Sie können es aber tun std::regex_search, siehe wandbox.org/permlink/rLbGyYcYGNsBWsaB
Jonathan Wakely