【问题标题】:What does std::match_results::size return?std::match_results::size 返回什么?
【发布时间】:2015-12-22 07:15:19
【问题描述】:

我对下面的 C++11 代码有点困惑:

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

int main()
{
    std::string haystack("abcdefabcghiabc");
    std::regex needle("abc");
    std::smatch matches;
    std::regex_search(haystack, matches, needle);
    std::cout << matches.size() << std::endl;
}

我希望它打印出3,但我得到的是1。我错过了什么吗?

【问题讨论】:

  • 每次搜索只能获得 1 个匹配项。

标签: c++ regex c++11


【解决方案1】:

您会得到1,因为regex_search 只返回1 个匹配项,而size() 将返回捕获组的数量+ 整个匹配值。

您的matches 是...:

match_results 类型的对象(例如 cmatch 或 smatch)由此函数填充,其中包含有关匹配结果和找到的任何子匹配的信息。

如果[正则表达式搜索]成功,它不为空并且包含一系列sub_match对象:第一个sub_match元素对应整个匹配,并且,如果正则表达式包含要匹配的子表达式(即,括号分隔的组),它们对应的子匹配作为连续的 sub_match 元素存储在 match_results 对象中。

这是一个可以找到多个匹配项的代码:

#include <string>
#include <iostream>
#include <regex>
using namespace std;
int main() {
  string str("abcdefabcghiabc");
  int i = 0;
  regex rgx1("abc");
  smatch smtch;
  while (regex_search(str, smtch, rgx1)) {
        std::cout << i << ": " << smtch[0] << std::endl;
        i += 1;
        str = smtch.suffix().str();
  }
  return 0;
}

看到IDEONE demo返回abc 3次。

由于此方法会破坏输入字符串,因此这是基于std::sregex_iterator 的另一种替代方法(当您的主题是std::wstring 对象时,应使用std::wsregex_iterator):

int main() {
    std::regex r("ab(c)");
    std::string s = "abcdefabcghiabc";
    for(std::sregex_iterator i = std::sregex_iterator(s.begin(), s.end(), r);
                             i != std::sregex_iterator();
                             ++i)
    {
        std::smatch m = *i;
        std::cout << "Match value: " << m.str() << " at Position " << m.position() << '\n';
        std::cout << "    Capture: " << m[1].str() << " at Position " << m.position(1) << '\n';
    }
    return 0;
}

IDEONE demo,返回

Match value: abc at Position 0
    Capture: c at Position 2
Match value: abc at Position 6
    Capture: c at Position 8
Match value: abc at Position 12
    Capture: c at Position 14

【讨论】:

  • 注意:上面的例子会破坏str,所以如果你需要保留它,请复制一份。重要的是获得smatch.suffix().str(),它返回匹配之后的文本。 while 循环在剩余的字符串上重复匹配,直到找不到更多匹配。
  • 是的,没错,为了保留str,只需使用它的副本。
  • @Morpheu5,如果还有什么不清楚的地方,请告诉我。
  • 我已经用另一种基于std::sregex_iterator 的方法更新了答案,该方法使所有(子)匹配项与其在输入字符串中的位置匹配。
【解决方案2】:

您缺少的是 matches 为每个捕获组填充了一个条目(包括作为第 0 个捕获的整个匹配子字符串)。

如果你写

std::regex needle("a(b)c");

然后你会得到matches.size()==2matches[0]=="abc"matches[1]=="b"

【讨论】:

    【解决方案3】:

    编辑:有些人对这个答案投了反对票。这可能有多种原因,但如果是因为它不适用于我批评的答案(没有人留下评论来解释决定),他们应该注意 W. Stribizew 两个月更改了代码 我写了这个之后,直到今天,2021-01-18,我才意识到它。其余的答案与我第一次写它时没有变化。

    @stribizhev 的解决方案对于正常的正则表达式具有二次最坏情况复杂性。对于疯狂的人(例如“y *”),它不会终止。在某些应用程序中,这些问题可能是DoS attacks 等待发生。这是一个固定版本:

    string str("abcdefabcghiabc");
    int i = 0;
    regex rgx1("abc");
    smatch smtch;
    auto beg = str.cbegin();
    while (regex_search(beg, str.cend(), smtch, rgx1)) {
        std::cout << i << ": " << smtch[0] << std::endl;
        i += 1;
        if ( smtch.length(0) > 0 )
            std::advance(beg, smtch.length(0));
        else if ( beg != str.cend() )
            ++beg;
        else
            break;
    }
    

    根据我的个人喜好,这将在长度为 n 的字符串中找到 n+1 个空正则表达式的匹配项。您也可以在空匹配后退出循环。

    如果您想比较具有数百万匹配项的字符串的性能,请在 str 的定义之后添加以下行(并且不要忘记打开优化),每个版本一次:

    for (int j = 0; j < 20; ++j)
        str = str + str;
    

    【讨论】:

      猜你喜欢
      • 2014-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多