首页 > 解决方案 > 正则表达式:在使用搜索 C++ 的否定方法时搜索不包括字符的组

问题描述

我正在使用默认的 Visual Studio 2017 社区版本。我刚刚完成了我的 bignum 实现的解析模型。但是现在我在向我的班级介绍公式时偶然发现了一个问题。这是一个字符串/正则表达式问题。

考虑这个带有变量和常量的字符串:

std::string formular_str = "1 + x * y / 2";

将此字符串传递给解析函数还需要一个 int 类型的向量(大小为 2,因为有 2 个变量)(在此示例中)

std::vector<int> vec{ 5, 4 };

因为这些被映射到变量 (xy)

在分解预处理过程之前,您需要了解我无法以某种方式过滤常量(12此示例中)"[0-9]+",因为我使用更高的基数,因此使用更多字符(来自 ASCII 的 152 个字符,准确无误)。这意味着我通过不存在运算符来定义数字(, +-为了这个例子)。它有效,因为这些运算符被排除在 bignum 基表之外。注意:变量遵循某种方式(在本例中)*/"[a-zA-Z]+[0-9]*"xy

为了使用运算符和非运算符字符串进行搜索,我删除了运算符附近的所有空格:

std::smatch matches;
std::regex reg_whitespace_near_operator("[\\s]+([\\+\\-\\*\\/])[\\s]+");
while (std::regex_search(formular_str, matches, reg_whitespace_near_operator, std::regex_constants::format_first_only)) {
    formular_str = std::regex_replace(formular_str, reg_whitespace_near_operator, matches.str(1), std::regex_constants::format_first_only);
}

formular_str( "1 + x * y / 2") 现在看起来像这样:"1+x*y/2"

接下来,我将所有变量 ( x, y)替换为#+ 递增索引。我#在解析中使用来表示vec.

std::regex reg_variable("[a-zA-Z]+[0-9]*");

unsigned ctr = 0;
while (std::regex_search(formular_str, reg_variable, std::regex_constants::format_first_only)) {
    formular_str = std::regex_replace(formular_str, reg_variable, std::string("#") + std::to_string(ctr++), std::regex_constants::format_first_only);
}

formular_str( "1+x*y/2") 现在看起来像这样:"1+#0*#1/2"

该模型将正确解释#0#1vec[0]vec[1]

最后,我希望我的字符串和向量看起来像这样:

"#2+#0*#1/#3"
{5, 4, 1, 2}

但这里是预处理失败的地方。尝试 push_back() 常量1 和向量,并在不陷入无限循环的情况下2替换它。#2#3

std::regex reg_constant("[^\\+\\-\\*\\/]+");
while (std::regex_search(formular_str, matches, reg_constant, std::regex_constants::format_first_only)) {
    //std::cout << "matches.str(0) = " << matches.str(0) << ", formular_str = " << formular_str << std::endl;
    vec.push_back(std::atoi(matches.str(0).c_str()));
    formular_str = std::regex_replace(formular_str, reg_constant, std::string("#") + std::to_string(ctr++), std::regex_constants::format_first_only);
}

这是一个无限循环:

matches.str(0) = 1, formular_str = 1+#0*#1/2
matches.str(0) = #2, formular_str = #2+#0*#1/2
matches.str(0) = #3, formular_str = #3+#0*#1/2
matches.str(0) = #4, formular_str = #4+#0*#1/2
matches.str(0) = #5, formular_str = #5+#0*#1/2
matches.str(0) = #6, formular_str = #6+#0*#1/2
matches.str(0) = #7, formular_str = #7+#0*#1/2
matches.str(0) = #8, formular_str = #8+#0*#1/2
...

第一场比赛是正确的,但它只是一直卡在第一个数字上。甚至达不到2。所以一个想法是像操作员一样对待#并将其从匹配中排除:

std::regex reg_constant("[^\\+\\-\\*\\/\\#]+");

产生这种模式:

matches.str(0) = 1, formular_str = 1+#0*#1/2
matches.str(0) = 2, formular_str = #2+#0*#1/2
matches.str(0) = 3, formular_str = ##3+#0*#1/2
matches.str(0) = 4, formular_str = ###4+#0*#1/2
matches.str(0) = 5, formular_str = ####5+#0*#1/2
matches.str(0) = 6, formular_str = #####6+#0*#1/2
matches.str(0) = 7, formular_str = ######7+#0*#1/2
matches.str(0) = 8, formular_str = #######8+#0*#1/2
...

我也试过std::sregex_iterator,但也卡住了。在这一点上我一无所知,我还考虑过在while循环内部使用多层过滤std::regex_searchstd::regex_replace但它失败了,因为它不会改变formular_str来打破while循环。所以它必须是正则表达式来识别正确的字符串,但我似乎无法让它正确。请帮我!

完整代码(带有额外的 std::couts)

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

int main() {
    std::vector<int> vec{ 5, 4 };
    std::string formular_str = "1 + x * y / 2";

    std::cout << "Starting formular: " << formular_str << std::endl;

    std::smatch matches;
    std::regex reg_whitespace_near_operator("[\\s]+([\\+\\-\\*\\/])[\\s]+");
    while (std::regex_search(formular_str, matches, reg_whitespace_near_operator, std::regex_constants::format_first_only)) {
        formular_str = std::regex_replace(formular_str, reg_whitespace_near_operator, matches.str(1), std::regex_constants::format_first_only);
    }
    std::cout << "Whitespace removed: " << formular_str << std::endl;

    std::regex reg_variable("[a-zA-Z]+[0-9]*");

    unsigned ctr = 0;
    while (std::regex_search(formular_str, reg_variable, std::regex_constants::format_first_only)) {
        formular_str = std::regex_replace(formular_str, reg_variable, std::string("#") + std::to_string(ctr++), std::regex_constants::format_first_only);
    }

    std::cout << "Variables replaced: " << formular_str << std::endl;

    std::regex reg_constant("[^\\+\\-\\*\\/]+");
    while (std::regex_search(formular_str, matches, reg_constant, std::regex_constants::format_first_only)) {
        std::cout << "matches.str(0) = " << matches.str(0) << ", formular_str = " << formular_str << std::endl;
        vec.push_back(std::atoi(matches.str(0).c_str()));
        formular_str = std::regex_replace(formular_str, reg_constant, std::string("#") + std::to_string(ctr++), std::regex_constants::format_first_only);
    }

    std::cout << "Finished formular: " << formular_str << std::endl;
}

标签: c++regexstring

解决方案


推荐阅读