c++ - 正则表达式:在使用搜索 C++ 的否定方法时搜索不包括字符的组
问题描述
我正在使用默认的 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;
}
解决方案
推荐阅读
- reactjs - 在基于 React 的设计系统中使用 FontAwesome 图标库
- google-api - 从 Google Drive 获取一个文件的内容,同时避免 Google 的安全评估
- javascript - 将 unix 时间戳转换为本地时间
- .net - .Net Core Web Windows 身份验证面向 500.30
- python - 当我在 Django 中创建 for 循环时,为什么我的 swipper 3d 滑块无法正常工作?
- c# - 未找到奇异化方法
- android - OpenGL ES 2.0 中多个对象的一对着色器
- rxjs - 通过将有效负载传递给 concatMapTo [actions] 在 NGX 效果中出现问题
- java - 从 itext 表格中删除嵌套表格边框
- ruby - 如何创建一个返回数组中回旋镖总数的函数