web-dev-qa-db-ja.com

gcc 4.8以前の正規表現に関するバグはありますか?

C++ 11のコードでstd :: regexを使用しようとしていますが、サポートには少しバグがあるようです。例:

#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

また、2つの代替パターンしかない場合、正規表現はうまく機能します。 st|mtので、最後の1つが何らかの理由で一致しないように見えます。コードは、Apple LLVMコンパイラでうまく機能します。

問題を解決する方法についてのアイデアはありますか?

更新 1つの可能な解決策は、グループを使用して複数の選択肢を実装することです。 (st|mt)|tr

97
tunnuz

<regex>はGCC 4.9.0で実装およびリリースされました。

GCCの(古い)バージョンでは、 実装されていません です。

そのプロトタイプ<regex>コードは、GCCのすべてのC++ 0xサポートがhighly実験的であり、初期のC++ 0xドラフトを追跡し、人々が実験できるようにしました。これにより、標準が完成する前に、人々は問題を見つけて標準委員会にフィードバックすることができました。当時、多くの人々が、C++ 11が完成するかなり前から、他の多くのコンパイラがanyサポートを提供する前に、Edgeの機能にアクセスできたことに感謝しており、そのフィードバックは本当に役に立ちましたC++ 11を改善します。これは良いことでしたTM

<regex>コードは決して有用な状態ではありませんでしたが、当時の他の多くのコードと同様に進行中の作業として追加されました。最終的に終了することを意図して、チェックインされ、他のユーザーが必要に応じてコラボレーションできるようになりました。

それはしばしばオープンソースの仕組みです: 早期リリース、頻繁にリリース -残念ながら<regex>の場合は、初期部分のみが適切であり、実装を終了する部分は多くありません。

ライブラリのほとんどの部分はより完全で、ほぼ完全に実装されていますが、<regex>はまだ実装されていないため、追加された後も未完成の状態のままでした。

しかし、真剣に、 "falseを返す"だけを行うregex_searchの実装を出荷することは良い考えでしたか?

C++ 0xがまだ進行中の作業であり、多くの部分的な実装を出荷した数年前は、それほど悪い考えではありませんでした。誰もそれがあまりにも長い間使えないだろうとは思わなかったので、後知恵で、多分それを無効にして、有効にするためにマクロまたは組み込みのオプションが必要だったはずです。しかし、その船はずっと前に出航しました。正規表現コードに依存するlibstdc ++。soライブラリからエクスポートされたシンボルがあるため、単純に削除する(たとえば、GCC 4.8)ことは簡単ではありません。

161
Jonathan Wakely

特徴検出

これは、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定義済み in bits/regex.tcc in 4.9.x
  • _GLIBCXX_REGEX_STATE_LIMIT定義済み in bits/regex_automatron.h in 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開発者が7.xリリースに#define _GLIBCXX_HAVE_WORKING_REGEX 1(または何か、ヒントヒントNudge nudge)を追加した場合、このスニペットを更新してそれを含めることができ、以降のGCCリリースは上記のスニペットで動作します。

私の知る限り、他のすべてのコンパイラは、<regex>がYMMVの場合に__cplusplus >= 201103Lが機能します。

誰かが_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMITまたは_GLIBCXX_REGEX_STATE_LIMITマクロをstdc++-v3ヘッダーの外側で定義した場合、これは明らかに完全に壊れます。

11
Matt Clarkson

現時点では(g ++(GCC)4.9.2でstd = c ++ 14を使用)、まだ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

0
Luis Orantes