gcc 4.8或更早版本对正则表达式有问题吗

Is gcc 4.8 or earlier buggy about regular expressions?

本文关键字:正则表达式 有问题 版本 gcc      更新时间:2023-10-16

我正试图在C++11代码中使用std::regex,但它的支持似乎有点bug。一个例子:

#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,那么regex也能很好地工作,所以由于某些原因,最后一个模式看起来不匹配。该代码与Apple LLVM编译器配合良好。

关于如何解决这个问题有什么想法吗?

更新一种可能的解决方案是使用组来实现多个备选方案,例如(st|mt)|tr

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

在GCC的旧版本中,它没有实现。

该原型<regex>代码是在GCC的所有C++0x支持都是高度实验性的时候添加的,跟踪早期的C++0x草案,并可供人们进行实验。这使人们能够在标准最终确定之前发现问题并向标准委员会提供反馈。当时,很多人都很感激早在C++11完成之前,在许多其他编译器提供任何支持之前,就已经获得了前沿功能,而这种反馈确实有助于改进C++11。这是一件好事TM

<regex>代码从未处于有用状态,而是像当时的许多其他代码一样作为正在进行的工作添加的。它被签入并提供给其他人合作,如果他们愿意的话,目的是最终完成。

开源通常就是这样工作的:尽早发布,经常发布——不幸的是,在<regex>的情况下,我们只得到了早期的部分,而没有得到通常会完成实现的部分。

库的大多数部分都更完整,现在几乎完全实现了,但<regex>还没有实现,所以自从添加以来,它一直处于未完成状态。

说真的,谁认为发布一个只会"返回false"的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是在4.9.xbits/regex.tcc中定义的
  • _GLIBCXX_REGEX_STATE_LIMIT5+中的bits/regex_automatron.h中定义
  • _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(或者其他什么,提示-提示-轻推-轻推),则可以更新此代码段以包含该代码段,并且以后的GCC版本将使用上面的代码段。

据我所知,所有其他编译器都有一个工作的<regex>,而__cplusplus >= 201103L是YMMV。

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

此时(在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