regex_match和regex_search有什么区别?

31

我正在尝试使用正则表达式来回答这个问题,并发现regex_match可以找到匹配项,但regex_search不能。

下面的程序是使用g++ 4.7.1编译的:

#include <regex>
#include <iostream>

int main()
{
    const std::string s = "/home/toto/FILE_mysymbol_EVENT.DAT";
    std::regex rgx(".*FILE_(.+)_EVENT\\.DAT.*");
    std::smatch match;

    if (std::regex_match(s.begin(), s.end(), rgx))
        std::cout << "regex_match: match\n";
    else
        std::cout << "regex_match: no match\n";

    if (std::regex_search(s.begin(), s.end(), match, rgx))
        std::cout << "regex_search: match\n";
    else
        std::cout << "regex_search: no match\n";
}

输出:

regex_match: 匹配
regex_search: 不匹配

我的假设认为两者都应该匹配是错的,或者在GCC 4.7.1库中可能存在问题吗?


9
GCC的正则表达式库仍然大部分未实现(GCC为什么要发布有缺陷的<regex>库?),因此我倾向于说,是该库存在问题。 - R. Martinho Fernandes
1
你的程序在VS2010中会出现两次匹配,因此我猜测问题可能出在gcc使用的库上。你尝试过使用boost版本的regex库吗? - MadScientist
1
@H2CO3 你也可以使用汇编语言,但你可能不想这样做 :) 对于包含在C++中的C函数也是一样。它们会破坏C++编程风格(例如,你需要开始检查返回代码,而不是关心异常)。 - betabandido
1
@H2CO3 当然可以,但目前我正在尝试了解新的C++11标准及其所有功能。在实际应用场景中,我可能会使用Boost或系统中可用的任何内容(例如标准POSIX功能)。 - Some programmer dude
1
@H2CO3 :) 如果我需要在实际代码中实现类似的东西,我肯定会使用POSIX正则表达式(或Boost.Regex)。但OP的问题很好。实际上,我想知道为什么GCC决定发布一个有缺陷的正则表达式实现。没有支持比有缺陷的支持更好... - betabandido
显示剩余11条评论
4个回答

11
假设C++和Boost Regex具有相似的结构和功能,regex_matchregex_search之间的区别在这里解释:

regex_match()算法只有在正则表达式从头到尾完全匹配输入时才报告成功。如果正则表达式仅匹配输入的一部分,则regex_match()将返回false。如果您想搜索字符串以查找正则表达式匹配的子字符串,请使用regex_search()算法。


7

你的正则表达式在VS 2012rc中运行良好(都匹配,这是正确的)。

在g++ 4.7.1 (-std=gnu++11)中,如果使用:

  • ".*FILE_(.+)_EVENT\\.DAT.*"regex_match匹配,但regex_search不匹配。
  • ".*?FILE_(.+?)_EVENT\\.DAT.*"regex_matchregex_search都不匹配(O_o)。

所有变体都应该匹配,但有些不匹配(已经被betabandido指出原因)。在g++ 4.6.3 (-std=gnu++0x)中,行为与g++ 4.7.1相同。

Boost(1.50)使用两种模式变体都可以完全匹配

总结

                        regex_match      regex_search
 -----------------------------------------------------
 g++ 4.6.3 linux            OK/-               -
 g++ 4.7.1 linux            OK/-               -
 vs 2010                     OK                OK
 vs 2012rc                   OK                OK
 boost 1.50 win              OK                OK
 boost 1.50 linux            OK                OK
 -----------------------------------------------------

关于您的模式,如果您想表示点字符'.',那么您应该这样写("\\.")。您还可以通过使用非贪婪修饰符(?)来减少回溯:

".*?FILE_(.+?)_EVENT\\.DAT.*"

4

查看最新的libstdc++ 源代码,你会发现:

* @todo Implement this function.

不幸的是,这不是唯一剩下的待办事项。GCC的<regex>实现目前还不完整。我建议使用Boost或Clang,并使用#ifdef代码,直到GCC追上为止。

(在4.8分支中也没有修复这个问题。)


2
我尝试在C++11中使用正则表达式库,但我遇到了许多问题(无论是使用g++ 4.6还是4.7都是如此)。基本上,支持要么不存在,要么仅有部分支持。即使对于SVN版本也是如此。这里有一个链接描述了libstdc++的SVN版本当前状态
因此,暂时来说,我认为最好的选择是继续使用Boost.Regex
或者,你可以尝试使用libc++。根据此文档,支持正则表达式是完整的。

clang 是一个编译器,而不是标准库 - 我想你的意思是使用 libc++。 - Jonathan Wakely
@JonathanWakely 的确。我以前从未使用过libc++,所以我认为它是clang的一部分。感谢您指出这一点。 - betabandido
它们都是LLVM项目的一部分。 - Jonathan Wakely

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