Есть ли ошибки в регулярных выражениях в gcc 4.8 или более ранней версии?

101

Я пытаюсь использовать std :: regex в фрагменте кода C ++ 11, но похоже, что поддержка немного глючна. Пример:

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

выходы:

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

при компиляции с помощью gcc (MacPorts gcc47 4.7.1_2) 4.7.1, либо с

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

или

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

Кроме того, регулярное выражение работает хорошо, если у меня есть только два альтернативных шаблона, например st|mt, поэтому похоже, что последний не соответствует по некоторым причинам. Код хорошо работает с компилятором Apple LLVM.

Есть идеи, как решить проблему?

Обновление. Одно из возможных решений - использовать группы для реализации нескольких альтернатив, например (st|mt)|tr.

Tunnuz
источник
9
Да, поддержка libstdc ++ <regex>неполная. Чем мы можем вам помочь?
kennytm
10
Чтобы regexузнать о статусе в libstdc ++, см. Gcc.gnu.org/onlinedocs/libstdc++/manual/…
ecatmur
52
А если серьезно, кто подумал, что доставка реализации regex_search, которая только возвращает false, была хорошей идеей? «О, мы это задокументировали» кажется слабым ответом.
Paul Rubel
4
@ AK4749: это не ошибка. Это просто нереализовано. Хотя количество случаев, когда этот вопрос появляется, вызывает тревогу, особенно с учетом того, что <regex>за последние 3-4 года в libstdc ++ ничего не изменилось (например, он остается нереализованным).
rubenvb
5
@KeithThompson, хотя это правда, что <regex>он предоставляется libstdc ++ (стандартная библиотека GCC) не gcc(интерфейс компилятора), он является частью GCC (проекта). См. «Libstdc ++ - v3 разработан и выпущен как часть GCC» . Если ваш дистрибутив решит разделить его на отдельный пакет, это не имеет ничего общего с GCC.
Джонатан Уэйкли,

Ответы:

170

<regex> был реализован и выпущен в GCC 4.9.0.

В вашей (более старой) версии GCC это не реализовано .

Этот прототип <regex> код был добавлен , когда все поддержка C ++ 0x GCC было весьма экспериментальным, отслеживание ранних C ++ 0x проектов и быть доступны для людей , чтобы экспериментировать с. Это позволяло людям находить проблемы и давать обратную связь комитету по стандарту до того, как стандарт был окончательно доработан. В то время многие люди были благодарны за доступ к новейшим функциям задолго до того, как был завершен C ++ 11 и до того, как многие другие компиляторы предоставили какую-либо поддержку, и эта обратная связь действительно помогла улучшить C ++ 11. Это была хорошая вещь TM .

<regex>Код никогда не был в состоянии полезного, но был добавлен в качестве работы в прогресс , как и многие другие биты кода в то время. Он был зарегистрирован и предоставлен другим пользователям для совместной работы, если они захотят, с намерением, чтобы в конечном итоге он был завершен.

Вот как часто работает открытый исходный код: выпускать раньше, выпускать часто - к сожалению, в случае, если <regex>мы получили правильную только раннюю часть, а не ту частую, которая завершила бы реализацию.

Большинство частей библиотеки были более полными и теперь почти полностью реализованы, но <regex>этого не произошло, поэтому с момента добавления она оставалась в том же незавершенном состоянии.

А если серьезно, кто подумал, что доставка реализации regex_search, которая только возвращает false, была хорошей идеей?

Это не было такой уж плохой идеей несколько лет назад, когда работа над C ++ 0x еще не завершена, и мы отправили множество частичных реализаций. Никто не думал, что он так долго будет оставаться непригодным для использования, поэтому, оглядываясь назад, возможно, его следовало отключить и для его включения требовался макрос или встроенный параметр времени. Но этот корабль давно отплыл. Существуют экспортированные символы из libstdc ++. Поэтому библиотека, которая зависит от кода регулярного выражения, поэтому простое ее удаление (например, в GCC 4.8) было бы нетривиальным.

Джонатан Уэйкли
источник
13

Обнаружение функции

Это фрагмент кода, позволяющий определить, libstdc++реализована ли реализация с помощью препроцессора C, определяемого:

#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

Макросы

  • _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMITбудет определен в bits/regex.tccв4.9.x
  • _GLIBCXX_REGEX_STATE_LIMITбудет определен в bits/regex_automatron.hв5+
  • _GLIBCXX_RELEASEбыл добавлен в 7+результате этого ответа и является основной версией GCC

Тестирование

Вы можете проверить это с помощью GCC следующим образом:

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

Полученные результаты

Вот некоторые результаты для разных компиляторов:


$ 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

Вот драконы

Это полностью не поддерживается и полагается на обнаружение частных макросов, которые разработчики GCC поместили в bits/regex*заголовки. Они могли измениться и уйти в любой момент . Надеюсь, они не будут удалены в текущих выпусках 4.9.x, 5.x, 6.x, но могут исчезнуть в выпусках 7.x.

Если разработчики GCC добавили #define _GLIBCXX_HAVE_WORKING_REGEX 1 (или что-то, подталкивающее подталкивание подсказки) в выпуске 7.x, который сохранился, этот фрагмент можно было бы обновить, включив его, и более поздние выпуски GCC будут работать с фрагментом выше.

Насколько я знаю, все остальные компиляторы имеют работу , <regex>когда , __cplusplus >= 201103Lно YMMV.

Очевидно, это полностью сломалось бы, если бы кто-то определил макросы _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMITили _GLIBCXX_REGEX_STATE_LIMITвне stdc++-v3заголовков.

Мэтт Кларксон
источник
Очень хорошо! Я собирался предложить проверить макрос защиты заголовка из одного из заголовков, который является новым в GCC 4.9, но у них нет защиты: - \ Макросы не меняются для GCC 7, но теоретически они могут работать для GCC 8+, поэтому, пожалуйста, отправьте запрос на улучшение на gcc.gnu.org/bugzilla с просьбой указать что-то вроде _GLIBCXX_REGEX_IS_OK_NOW_KTHXBAIзаголовков, чтобы это не забылось - спасибо!
Джонатан Уэйкли,
1
@JonathanWakely добавил 78905 . Я не уверен, как превратить это в ошибку улучшения, но теперь она в системе.
Мэтт Кларксон,
1

В настоящий момент (используя std = c ++ 14 в g ++ (GCC) 4.9.2) все еще не принимает regex_match.

Вот подход, который работает как regex_match, но вместо этого использует sregex_token_iterator. И это работает с 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;

он напечатает 1 2 3

вы можете прочитать ссылку sregex_token_iterator в: http://en.cppreference.com/w/cpp/regex/regex_token_iterator

Луис Орантес
источник
1
«В настоящий момент (используя std = c ++ 14 в g ++ (GCC) 4.9.2) все еще не принимает regex_match». Это неправда, возможно, вы неправильно это используете.
Джонатан
1
Ваш код не является «подходом, который работает как regex_match», потому что эта функция пытается сопоставить подстроки, а не всю строку, поэтому я все еще думаю, что вы используете ее неправильно. Вы можете сделать это с помощью std::regex_search, см. Wandbox.org/permlink/rLbGyYcYGNsBWsaB
Джонатан