正则表达式:使用搜索C ++的否定方法来搜索不包含字符的组

时间:2018-08-10 16:14:28

标签: c++ regex string

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

将此字符串与变量和常量一起考虑:

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

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

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

因为它们被映射到变量(xy

在分解预处理过程之前,您需要了解,我无法以1的方式过滤常量(在此示例中为2"[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"

接下来,我将所有变量(xy)替换为# +递增索引。 我在解析时使用#来表示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#1解释为vec[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;
}

0 个答案:

没有答案