std::regex中存在Bug吗?

6

这里是代码:

#include <string>
#include <regex>
#include <iostream>

int main()
{
    std::string pattern("[^c]ei");
    pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*";
    std::regex r(pattern); 
    std::smatch results;   
    std::string test_str = "cei";

    if (std::regex_search(test_str, results, r)) 
        std::cout << results.str() << std::endl;      

    return 0;
}

输出:

cei

编译器使用的是gcc 4.9.1
我是一个刚开始学习正则表达式的新手。我期望输出应该为空,因为 "cei" 在此处与模式不匹配。我做得对吗?问题出在哪里?
更新:
这个问题已经被报告并确认为一个 bug,请访问此处获取详细信息: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63497

clang++可以运行(libc++), gcc无法运行(stdlibc++)... http://coliru.stacked-crooked.com/a/fc56ed8c533bda55 - Niall
谢谢 @rubberboots 我会尝试使用 boost - Yue Wang
@Alan.W [[:alpha:]]* 会吃掉所有字符。然后,匹配器就没有剩下的 cei,因为它已经在末尾了。通过回溯,字符串应该能够匹配... - rubber boots
1
@Alan.W 在我看来,使用 C++ 库学习正则表达式过于困难且易混淆,因为其风格和表达方式中存在 C++ 的专有术语。我建议你使用 Perl 学习正则表达式,并逐渐将工作表达式转换到 C++ 中。可以参考这本书:http://regex.info/ - rubber boots
1
@Alan.W http://perldoc.perl.org/perlretut.html - rubber boots
显示剩余15条评论
2个回答

4

这是实现上的bug。不仅我尝试过的其他几个工具也认为您的模式与输入不匹配,而且我还尝试了以下内容:

#include <string>
#include <regex>
#include <iostream>

int main()
{
  std::string pattern("([a-z]*)([a-z])(e)(i)([a-z]*)");
  std::regex r(pattern);
  std::smatch results;
  std::string test_str = "cei";

  if (std::regex_search(test_str, results, r))
  {
    std::cout << results.str() << std::endl;

    for (size_t i = 0; i < results.size(); ++i) {
      std::ssub_match sub_match = results[i];
      std::string sub_match_str = sub_match.str();
      std::cout << i << ": " << sub_match_str << '\n';
    }
  }
}

这与您之前的类似,但我将[:alpha:]替换为 [a-z] 以简化操作。我还暂时将[^c]替换为[a-z] ,因为这似乎可以使其正常工作。这是它在Linux x86-64上的GCC 4.9.0的输出结果:

cei
0: cei
1:
2: c
3: e
4: i
5:

如果我将你的 [^c] 替换为 [a-z] ,并在那里放上 f ,它会正确地显示模式不匹配。但是如果我像你一样使用 [^c]

std::string pattern("([a-z]*)([^c])(e)(i)([a-z]*)");

然后我得到了这个输出:

cei
0: cei
1: cei
terminate called after throwing an instance of 'std::length_error'
  what():  basic_string::_S_create
Aborted (core dumped)

因此,它声称匹配成功,results[0]是"cei",这是预期的。然后,results[1]也是"cei",我想这可能是可以的。但是,results[2]会崩溃,因为它尝试使用begin=nullptr构造长度为18446744073709551614的std::string。那个巨大的数字恰好是2 ^ 64-2,也就是std::string :: npos-1(在我的系统上)。所以我认为某个地方有一个偏移量错误,其影响可能远不止一个虚假的正则表达式匹配 - 它可能会在运行时崩溃。

谢谢!我用你的代码得到了完全相同的结果。我猜我需要使用Clang或者改用boost - Yue Wang
2
@Alan.W:或者你可以稍微改一下正则表达式的写法。我试过几个和这个差不多的表达式都能正常工作。你想要为此提交GCC的错误报告吗?我认为你应该这么做。 - John Zwinck
太酷了,我会尝试不同的模式。报告 Bug?我可以吗?如何报告这种问题?你可以分享一个链接或一些东西,让我学习如何报告这个 Bug 吗? - Yue Wang
1
@Alan.W:这是链接:https://gcc.gnu.org/bugzilla/enter_bug.cgi?product=gcc - 你需要创建一个账户。很容易的,不要害怕。 :) - John Zwinck
我发现 Bug 61720 很相似: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61720. 你能看一下吗?我还需要报告这个 Bug 吗? - Yue Wang
显示剩余4条评论

2

正则表达式正确的,不应该匹配字符串“cei”。

在Perl中,最好可以测试和解释正则表达式:

 my $regex = qr{                 # start regular expression
                 [[:alpha:]]*    # 0 or any number of alpha chars
                 [^c]            # followed by NOT-c character
                 ei              # followed by e and i characters
                 [[:alpha:]]*    # followed by 0 or any number of alpha chars    
               }x;               # end + declare 'x' mode (ignore whitespace)

 print "xei" =~ /$regex/ ? "match\n" : "no match\n";
 print "cei" =~ /$regex/ ? "match\n" : "no match\n";

正则表达式首先会消耗所有字符直到字符串末尾([[:alpha:]]*),然后回溯查找非c字符[^c]并继续匹配e和i(通过再次回溯)。
 "xei"  -->  match
 "cei"  -->  no match

由于明显的原因,任何C++库和测试工具中与此不符的差异都是其实现本身的问题,个人认为。


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