Apakah gcc 4.8 atau sebelumnya bermasalah dengan ekspresi reguler?

101

Saya mencoba menggunakan std :: regex dalam kode C ++ 11, tetapi tampaknya dukungannya agak bermasalah. Sebuah contoh:

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

keluaran:

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

ketika dikompilasi dengan gcc (MacPorts gcc47 4.7.1_2) 4.7.1, baik dengan

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

atau

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

Selain itu, regex berfungsi dengan baik jika saya hanya memiliki dua pola alternatif, misalnya st|mt, jadi sepertinya yang terakhir tidak cocok karena beberapa alasan. Kode bekerja dengan baik dengan kompiler LLVM Apple.

Ada ide tentang cara mengatasi masalah ini?

Perbarui satu solusi yang mungkin adalah dengan menggunakan grup untuk mengimplementasikan beberapa alternatif, misalnya (st|mt)|tr.

tunnuz
sumber
9
Ya, <regex>dukungan libstdc ++ tidak lengkap. Apa yang bisa kami bantu?
kennytm
10
Untuk status regexdi libstdc ++, lihat gcc.gnu.org/onlinedocs/libstdc++/manual/…
ecatmur
51
Serius, menurut siapa yang mengirimkan implementasi regex_search yang hanya menghasilkan "return false" adalah ide yang bagus? "Oh, kami mendokumentasikannya" sepertinya jawaban yang lemah.
Paul Rubel
4
@ AK4749: ini bukan kesalahan. Itu benar-benar tidak diterapkan. Meskipun frekuensi munculnya pertanyaan ini mengkhawatirkan, terutama karena tidak ada yang berubah tentang libstdc ++ <regex>dalam 3-4 tahun terakhir (seperti: tetap tidak diterapkan).
rubenvb
5
@KeithThompson, meskipun benar yang <regex>disediakan oleh libstdc ++ (pustaka standar GCC) bukan gcc(ujung depan kompilator), ini adalah bagian dari GCC (proyek). Lihat "libstdc ++ - v3 dikembangkan dan dirilis sebagai bagian dari GCC" . Jika distro Anda memilih untuk membaginya menjadi paket terpisah, itu tidak ada hubungannya dengan GCC.
Jonathan Wakely

Jawaban:

168

<regex> diimplementasikan dan dirilis di GCC 4.9.0.

Di GCC versi (lama) Anda, ini tidak diterapkan .

<regex>Kode prototipe tersebut ditambahkan ketika semua dukungan C ++ 0x GCC sangat eksperimental, melacak draf C ++ 0x awal dan tersedia bagi orang-orang untuk bereksperimen. Hal itu memungkinkan orang untuk menemukan masalah dan memberikan umpan balik kepada panitia standar sebelum standar diselesaikan. Pada saat itu, banyak orang bersyukur telah memiliki akses ke fitur-fitur terbaru jauh sebelum C ++ 11 selesai dan sebelum banyak kompiler lain memberikan dukungan apa pun , dan umpan balik tersebut sangat membantu meningkatkan C ++ 11. Ini adalah Good Thing TM .

The <regex>kode tidak pernah dalam keadaan berguna, tetapi ditambahkan sebagai karya-in-progress seperti banyak potongan lain kode pada saat itu. Itu diperiksa dan tersedia bagi orang lain untuk berkolaborasi jika mereka mau, dengan maksud bahwa itu akan selesai pada akhirnya.

Begitulah cara kerja open source: Rilis lebih awal, sering rilis - sayangnya dalam kasus ini <regex>kami hanya mendapatkan bagian awal yang benar dan bukan bagian yang sering menyelesaikan implementasi.

Sebagian besar pustaka lebih lengkap dan sekarang hampir sepenuhnya diimplementasikan, tetapi <regex>belum, jadi pustaka tetap dalam keadaan belum selesai yang sama sejak ditambahkan.

Serius, menurut siapa yang mengirimkan implementasi regex_search yang hanya menghasilkan "return false" adalah ide yang bagus?

Beberapa tahun yang lalu, ini bukanlah ide yang buruk, ketika C ++ 0x masih dalam proses dan kami mengirimkan banyak implementasi parsial. Tidak ada yang mengira itu akan tetap tidak dapat digunakan begitu lama jadi, dengan melihat ke belakang, mungkin itu seharusnya dinonaktifkan dan membutuhkan opsi makro atau waktu bawaan untuk mengaktifkannya. Tapi kapal itu sudah lama berlayar. Ada simbol yang diekspor dari libstdc ++. Jadi pustaka yang bergantung pada kode regex, jadi cukup menghapusnya (dalam, katakanlah, GCC 4.8) tidak akan sepele.

Jonathan Wakely
sumber
12

Deteksi Fitur

Ini adalah potongan untuk mendeteksi jika libstdc++implementasi diimplementasikan dengan C preprocessor mendefinisikan:

#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

Makro

  • _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMITadalah didefinisikan di bits/regex.tccdalam4.9.x
  • _GLIBCXX_REGEX_STATE_LIMITadalah didefinisikan di bits/regex_automatron.hdalam5+
  • _GLIBCXX_RELEASEditambahkan ke 7+sebagai hasil dari jawaban ini dan merupakan versi utama GCC

Menguji

Anda dapat mengujinya dengan GCC seperti ini:

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

Hasil

Berikut beberapa hasil untuk berbagai kompiler:


$ 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

Ini Naga

Ini sama sekali tidak didukung dan bergantung pada deteksi makro pribadi yang telah dimasukkan oleh pengembang GCC ke dalam bits/regex*header. Mereka bisa berubah dan pergi kapan saja . Mudah-mudahan, mereka tidak akan dihapus di rilis 4.9.x, 5.x, 6.x saat ini tetapi mereka bisa hilang di rilis 7.x.

Jika pengembang GCC menambahkan #define _GLIBCXX_HAVE_WORKING_REGEX 1(atau sesuatu, petunjuk petunjuk dorongan) dalam rilis 7.x yang bertahan, cuplikan ini dapat diperbarui untuk menyertakannya dan rilis GCC selanjutnya akan bekerja dengan cuplikan di atas.

Sejauh yang saya tahu, semua kompiler lainnya memiliki kerja <regex>saat __cplusplus >= 201103Ltapi YMMV.

Jelas ini akan benar-benar rusak jika seseorang mendefinisikan _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMITatau _GLIBCXX_REGEX_STATE_LIMITmakro di luar stdc++-v3tajuk.

Matt Clarkson
sumber
Sangat bagus! Saya akan menyarankan untuk memeriksa makro pelindung tajuk dari salah satu tajuk yang baru di GCC 4.9, tetapi tidak memiliki pelindung: - \ Makro tidak berubah untuk GCC 7, tetapi secara teoritis dapat dilakukan untuk GCC 8+, jadi harap ajukan permintaan peningkatan di gcc.gnu.org/bugzilla meminta sesuatu seperti _GLIBCXX_REGEX_IS_OK_NOW_KTHXBAIdi header, agar tidak terlupakan - terima kasih!
Jonathan Wakely
1
@JonathanWakely telah menambahkan 78905 . Saya tidak yakin bagaimana membuatnya menjadi bug peningkatan tetapi sekarang ada di sistem.
Matt Clarkson
1

Saat ini (menggunakan std = c ++ 14 di g ++ (GCC) 4.9.2) masih belum menerima regex_match.

Berikut adalah pendekatan yang bekerja seperti regex_match tetapi menggunakan sregex_token_iterator sebagai gantinya. Dan itu bekerja dengan 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;

itu akan mencetak 1 2 3

Anda dapat membaca referensi sregex_token_iterator di: http://en.cppreference.com/w/cpp/regex/regex_token_iterator

Luis Orantes
sumber
1
"Saat ini (menggunakan std = c ++ 14 di g ++ (GCC) 4.9.2) masih belum menerima regex_match." Itu tidak benar, Anda mungkin salah menggunakannya.
Jonathan Wakely
1
Kode Anda bukanlah "pendekatan yang bekerja seperti regex_match" karena fungsi itu mencoba mencocokkan sub-string, bukan keseluruhan string, jadi saya masih berpikir Anda salah menggunakannya. Anda dapat melakukannya dengan std::regex_search, lihat wandbox.org/permlink/rLbGyYcYGNsBWsaB
Jonathan Wakely