gcc 4.8或更早版本在正则表达式方面存在问题吗?

107

我正在尝试在一个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

使用MacPorts gcc47 4.7.1_2版本的gcc编译时,无论是用

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

9
是的,libstdc++的<regex>支持不完整。我们能为您提供哪些帮助? - kennytm
10
有关libstdc++regex状态的信息,请参见http://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.2011。 - ecatmur
60
说真的,谁想过只实现“返回false”的regex_search是一个好主意?“哦,我们有文档记录”似乎是一个很弱的回答。 - Paul Rubel
5
@AK4749说:“这并不是错误,只是没有实现而已。虽然这个问题出现的次数令人担忧,尤其是自从过去3-4年里libstdc++ <regex>没有任何改变(也就是说,它仍然没有被实现)。" - rubenvb
6
虽然 @KeithThompson 的说法没错,"<regex>" 是由 libstdc++ (GCC 标准库)而不是 gcc(编译器前端)提供的,但它是 GCC 项目的一部分。请参见"libstdc++-v3 is developed and released as part of GCC"。如果您的发行版选择将其拆分为单独的软件包,则与 GCC 无关。 - Jonathan Wakely
显示剩余10条评论
3个回答

179

<regex>在GCC 4.9.0中实现并发布。

在您的(旧)GCC版本中,它未实现

当时,GCC的C++0x支持是高度实验性的,跟踪早期的C++0x草案,并提供给人们进行实验。这允许人们在标准最终确定之前发现问题并向标准委员会提供反馈。当时,很多人感激能够在C++11完成之前和许多其他编译器没有提供任何支持之前就拥有了前沿特性,而这些反馈真正帮助改进了C++11。这是一件好事。

<regex>代码从未处于有用的状态,但像当时许多其他代码一样作为正在进行的工作添加到其中。它被检查并提供给其他人进行协作,如果他们愿意,以期最终完成它。

这通常是开源软件的工作方式:早发布,常发布 - 不幸的是,在<regex>的情况下,我们只做到了前半部分,而没有完成实现。

库的大多数部分都更完整,现在几乎完全实现了,但是<regex>尚未实现,因此自添加以来一直保持在同样未完成的状态。

然而,谁会认为仅执行“返回false”的regex_search实现是一个好主意呢?

几年前,当C++0x仍处于进展阶段并且我们发布了许多部分实现时,这并不是一个坏主意。当时没有人认为它会长期无法使用,所以事后看来,也许应该禁用它并要求使用宏或构建时选项来启用它。但是,这艘船早就开走了。来自libstdc++.so库的导出符号依赖于正则表达式代码,因此仅仅简单地删除它(例如在GCC 4.8中)将不是一件容易的事情。


15

特性检测

以下是用于检测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_LIMIT4.9.x 中在 bits/regex.tcc 中被定义
  • _GLIBCXX_REGEX_STATE_LIMIT5+ 中在 bits/regex_automatron.h 中被定义
  • _GLIBCXX_RELEASE 是 GCC 主要版本,在7+中因此答案而添加

测试

您可以使用 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(或类似的,暗示暗示)并保持不变,那么可以更新这个代码片段以包含它,后续的GCC版本将与上述代码片段一起工作。

据我所知,所有其他编译器都在__cplusplus >= 201103L时具有可用的<regex>,但你的情况可能有所不同。

显然,如果有人在stdc++-v3头文件之外定义了_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT_GLIBCXX_REGEX_STATE_LIMIT宏,这将完全破坏。


1
非常好!我本来想建议从GCC 4.9中的一个新头文件中检查头保护宏,但是它们没有保护符:-\ 这些宏在GCC 7中不会改变,但理论上它们可能会在GCC 8+中发生变化,因此请在https://gcc.gnu.org/bugzilla上提交增强请求,要求在头文件中添加类似`_GLIBCXX_REGEX_IS_OK_NOW_KTHXBAI`的内容,以免被遗忘-谢谢! - Jonathan Wakely
2
@JonathanWakely已添加78905。我不确定如何将其转换为增强错误,但现在已经在系统中了。 - Matt Clarkson

0

目前(在使用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的参考文献。


2
此刻(在使用GCC 4.9.2中的std=c++14时),仍然无法接受regex_match。那不是真的,你可能使用方法不正确。 - Jonathan Wakely
2
你的代码不是“像regex_match一样工作的方法”,因为该函数尝试匹配子字符串,而不是整个字符串,所以我仍然认为你使用它是错误的。但你可以使用std::regex_search来实现,参见https://wandbox.org/permlink/rLbGyYcYGNsBWsaB - Jonathan Wakely

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接