我正在使用默认的Visual Studio 2017社区版本。我刚刚为bignum实现完成了解析模型。 在向我的班级介绍配方设计师时,我偶然发现了一个问题。这是一个字符串/正则表达式问题。
将此字符串与变量和常量一起考虑:
std::string formular_str = "1 + x * y / 2";
将此字符串传递给解析函数还需要一个int类型的向量(大小为2,因为有2个变量)
std::vector<int> vec{ 5, 4 };
因为它们被映射到变量(x
和y
)
在分解预处理过程之前,您需要了解,我无法以1
的方式过滤常量(在此示例中为2
和"[0-9]+"
),因为我使用的是更高的基数,因此使用了更多的字符(准确来说是ASCII中的152个字符)。这意味着我通过缺少运算符来定义数字(在此示例中,+
,-
,*
和/
)。之所以可行,是因为这些运算符已从bignum基表中排除。注意:变量遵循"[a-zA-Z]+[0-9]*"
的方式(在此示例中为x
和y
)
为了使用运算符和非运算符字符串进行搜索,我删除了运算符附近的所有空格:
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
和#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_search
和std::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;
}