C++11正则表达式匹配捕获组多次使用

4
请问能否使用JavaScript(ECMAScript)正则表达式在C++11中提取冒号和插入符号之间的文本?我不需要捕获hw-descriptor本身,但必须确保该行中存在hw-descriptor以便查找后续匹配项。此外,:p....^:m....^:u....^可以按任意顺序出现,并且至少要有一个存在。
我尝试使用以下正则表达式:
static const std::regex gRegex("(?:hw-descriptor)(:[pmu](.*?)\\^)+", std::regex::icase);

针对以下文本行:

"hw-descriptor:pTEXT1^:mTEXT2^:uTEXT3^"

这里是贴在live coliru上的代码。它展示了我尝试解决这个问题的方式,但是我只得到了1个匹配结果。我需要知道如何提取之前所述的对应于p m或u字符的每个潜在的3个匹配结果。
#include <iostream>
#include <string>
#include <vector>
#include <regex>

int main()
{
    static const std::regex gRegex("(?:hw-descriptor)(:[pmu](.*?)\\^)+", std::regex::icase);
    std::string foo = "hw-descriptor:pTEXT1^:mTEXT2^:uTEXT3^";
    // I seem to only get 1 match here, I was expecting 
    // to loop through each of the matches, looks like I need something like 
    // a pcre global option but I don't know how.
    std::for_each(std::sregex_iterator(foo.cbegin(), foo.cend(), gRegex), std::sregex_iterator(), 
        [&](const auto& rMatch) {
            for (int i=0; i< static_cast<int>(rMatch.size()); ++i) {
                std::cout << rMatch[i] << std::endl;
            }
        });
}

上面的程序输出如下:
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
hw-descriptor:pTEXT1^:mTEXT2^:uTEXT3^
:uTEXT3^
TEXT3

1
你没有说明在 blocks 之间是否可以有任何内容。然而,这是一个两步过程,第一步是验证和捕获所有块,第二步是提取单个块。第一步 ^(?:hw-descriptor)(.*?:[pmu]\^.*),第二步 :([pmu])(.*?)\^,第二步使用第一步的捕获缓冲区作为目标字符串,并进行全局操作。 - user557597
否则你可能想使用 Boost 库。在那里,你可以使用基于 \G 的正则表达式,甚至可以访问捕获集合(参见 http://www.boost.org/doc/libs/1_33_1/libs/regex/doc/captures.html)。 - Wiktor Stribiżew
1
或者更高版本的boost regex:http://www.boost.org/doc/libs/1_61_0/libs/regex/doc/html/boost_regex/captures.html。我建议你现在坚持你已经有的方法,分两步来完成。其他选项可能会成为你的链接和设置噩梦。如果你需要比ecmascript更强大的功能,那么使用pcre或类似boost-perl的东西可能是值得的。请注意,boost regex重复捕获最多只能算是有问题(请参见性能免责声明)。 - user557597
嗯,对于提升选项很感兴趣,因为该应用程序目前正在使用boost 1.61,不错。 - johnco3
同意,但实际的正则表达式要复杂得多,因为它匹配了 FTP 服务器响应中的多个横幅。正则表达式给了我很大的灵活性。 - johnco3
显示剩余8条评论
1个回答

5

使用 std::regex,在匹配连续重复的模式字符串时,无法保留多个重复捕获。

你可以匹配包含前缀和重复块的整个文本,将后者捕获到一个单独的组中,然后使用第二个更小的正则表达式单独获取所需子字符串的所有出现。

这里的第一个正则表达式可能是:

hw-descriptor((?::[pmu][^^]*\\^)+)

请查看在线演示。它将匹配hw-descriptor,并且((?::[pmu][^^]*\\^)+)会捕获一个或多个:[pmu][^^]*\^模式的重复内容,并保存到第一组中::p/m/u,0个或更多的字符(不包括^)和^。 找到匹配后,使用:[pmu][^^]*\^正则表达式返回所有真实的“匹配项”。
请参见C++演示
static const std::regex gRegex("hw-descriptor((?::[pmu][^^]*\\^)+)", std::regex::icase);
static const std::regex lRegex(":[pmu][^^]*\\^", std::regex::icase);
std::string foo = "hw-descriptor:pTEXT1^:mTEXT2^:uTEXT3^ hw-descriptor:pTEXT8^:mTEXT8^:uTEXT83^";
std::smatch smtch;
for(std::sregex_iterator i = std::sregex_iterator(foo.begin(), foo.end(), gRegex);
                         i != std::sregex_iterator();
                         ++i)
{
    std::smatch m = *i;
    std::cout << "Match value: " << m.str() << std::endl;
    std::string x = m.str(1);
    for(std::sregex_iterator j = std::sregex_iterator(x.begin(), x.end(), lRegex);
                         j != std::sregex_iterator();
                         ++j)
    {
        std::cout << "Element value: " << (*j).str() << std::endl;
    }
}

输出:

Match value: hw-descriptor:pTEXT1^:mTEXT2^:uTEXT3^
Element value: :pTEXT1^
Element value: :mTEXT2^
Element value: :uTEXT3^
Match value: hw-descriptor:pTEXT8^:mTEXT8^:uTEXT83^
Element value: :pTEXT8^
Element value: :mTEXT8^
Element value: :uTEXT83^

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