C ++正则表达式:获取SubMatch匹配的Capture Group的索引

时间:2018-01-12 21:52:58

标签: c++ regex tokenize lexer capturing-group

上下文。我正在开发一个Lexer / Tokenizing引擎,它将使用正则表达式作为后端。词法分析器接受定义令牌类型/ ID的规则,例如

task copyall(){ println 'starting...' task copyA(type: Copy) { mkdir 'web' from 'src' into 'web' } }

正如我所设想的那样,要进行基于正则表达式匹配的标记化,正则表达式定义的所有规则都包含在捕获组中,并且所有组都由OR分隔。

当执行匹配时,我们生成的每个匹配必须具有与其匹配的捕获组的索引。我们使用这些ID将匹配映射到令牌类型。

因此出现了这个问题的问题 - 如何获取群组的ID

Similar question此处,但它不能解决我的具体问题。

正是我的问题here,但它在JS中,我需要一个C / C ++解决方案。

所以,假设我有一个正则表达式,由捕获由OR分隔的组组成:

<identifier> = "\\b\\w+\\b"

匹配整数或字母。

我的问题要求正则表达式匹配的捕获组的索引可以是已知的,例如匹配字符串时

(\\b[a-zA-Z]+\\b)|(\\b\\d+\\b)

将完成3次迭代。每次迭代的匹配的组索引将是foo bar 123,因为前两个匹配匹配第一个捕获组,最后一个匹配匹配第二个捕获组。

我知道在标准0 0 1库中并不完全可能(std::regex不是解决方案,因为我不需要跳过任何匹配。)

我对regex_token_iterator或PCRE正则表达式库没有太多了解。

完成此任务的最佳方法是什么?哪个库和方法可以使用?

1 个答案:

答案 0 :(得分:2)

您可以使用sregex_iterator获取所有匹配项,一旦匹配,您可以分析std::match_results结构并仅获取非空的组的ID-1值(仅匹配的一个组将是非空的:

std::regex r(R"((\b[[:alpha:]]+\b)|(\b\d+\b))");
std::string s = "foo bar 123";
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';

    for(auto index = 1; index < m.size(); ++index ){
        if (!m[index].str().empty()) {
            std::cout << "Capture group ID: " << index-1 << std::endl;
            break;
        }
    }
}

请参阅C++ demo。输出:

Match value: foo at Position 0
Capture group ID: 0
Match value: bar at Position 4
Capture group ID: 0
Match value: 123 at Position 8
Capture group ID: 1

请注意R"(...)"是一个原始字符串文字,不需要在其中加倍反斜杠。

此外,index1循环开始时设置为for,因为第0组是整个匹配,但您希望组ID从零开始,这就是为什么1稍后被删除的原因。