gcc 4.8 또는 이전 버전은 정규 표현식에 대해 버그가 있습니까? (int argc, const char *

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

게다가, 예를 들어 두 개의 대체 패턴 만 있으면 정규식이 잘 작동 st|mt하므로 몇 가지 이유로 마지막 패턴 이 일치하지 않는 것처럼 보입니다. 이 코드는 Apple LLVM 컴파일러에서 잘 작동합니다.

문제를 해결하는 방법에 대한 아이디어가 있습니까?

업데이트 하나 개의 가능한 솔루션은, 예를 들어, 여러 대안을 구현하기 위해 그룹을 사용하는 것입니다 (st|mt)|tr.



답변

<regex> GCC 4.9.0에서 구현 및 출시되었습니다.

(이전) 버전의 GCC에서는 구현되지 않습니다 .

이 프로토 타입 <regex>코드는 GCC의 모든 C ++ 0x 지원이 매우 실험적이어서 초기 C ++ 0x 초안을 추적하고 사람들이 실험 할 수있게 되었을 때 추가되었습니다 . 이를 통해 사람들은 표준이 확정되기 전에 문제를 발견하고 표준위원회에 피드백을 제공 할 수있었습니다. 당시 많은 사람들은 가장자리 출혈 (11)가 끝난 후 많은 다른 컴파일러 전에 제공 ++ C 전에 긴 특징을 가지고 접근해야 할 감사했다 어떤 지원을하고, 그 피드백은 정말 C ++ (11)을 향상 도움을. 이것은 좋은 일 TM 이었습니다.

<regex>코드는 유용한 상태에서 결코 없지만, 작업 진행시에 코드의 다른 많은 비트 등 추가되었습니다. 최종적으로 완료 될 것이라는 의도로 체크인하여 다른 사람들이 원하는 경우 공동 작업 할 수 있도록했습니다.

그것은 종종 어떻게 오픈 소스 작품이다 : 릴리스 일찍, 자주 출시 – 불행히도의 경우 <regex>우리 만 구현을 완료했을 종종 부분을 초반 권리를 가지고하지.

라이브러리의 대부분은 더 완벽했고 이제 거의 완전히 구현되었지만 아직 구현 <regex>되지 않았으므로 추가 된 이후 동일한 미완성 상태로 유지되었습니다.

진지하게, “거짓 반환”만하는 regex_search 구현을 제공하는 것이 좋은 생각이었던 사람은 누구입니까?

몇 년 전에는 C ++ 0x가 여전히 작업 중이었고 많은 부분적 구현을 ​​제공했을 때는 그렇게 나쁜 생각이 아니 었습니다. 아무도 그것이 그렇게 오랫동안 사용할 수 없을 것이라고 생각하지 않았기 때문에, 돌이켜 보면 아마도 비활성화되어야했고 활성화하려면 매크로 또는 빌드 타임 옵션이 필요했을 것입니다. 하지만 그 배는 오래 전에 항해했습니다. 정규식 코드에 의존 하는 libstdc ++. so 라이브러리 에서 내 보낸 기호가 있으므로 단순히 제거 (예 : GCC 4.8)하는 것은 사소한 일이 아닙니다.


답변

기능 감지

이것은 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 릴리스는 위의 코드 조각과 함께 작동합니다.

지금까지 내가 아는 한, 다른 컴파일러가 작동해야 하지만 YMMV을.<regex>__cplusplus >= 201103L

누군가 헤더 외부 에서 _GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT또는 _GLIBCXX_REGEX_STATE_LIMIT매크로를 정의하면 분명히 이것은 완전히 중단됩니다 stdc++-v3.


답변

현재 (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을 인쇄합니다.

http://en.cppreference.com/w/cpp/regex/regex_token_iterator 에서 sregex_token_iterator 참조를 읽을 수 있습니다
.