C++实现中缀表达式正确性校验的方法与代码答疑
C++中缀表达式输入合法性完整校验实现
你原有写的校验逻辑存在硬编码偏移、规则覆盖不全的问题,比如强制要求首尾必须为括号就不符合中缀表达式语法,固定按位置偏移判断邻接字符完全无法适配多位数、括号嵌套、一元运算符的场景。完整的校验需要从字符合法、括号匹配、词法切分、语法顺序四个维度逐层判断,用状态机+栈的结构实现,不需要硬编码字符位置。
核心校验规则
- 字符合法性:表达式仅允许出现数字、
+-*/%^运算符、左右括号、空格,其余字符均为非法 - 括号匹配:用栈结构存储遍历到的左括号,遇到右括号时栈空则右括号多余,遍历完成栈非空则左括号多余,同时禁止空括号、括号内直接跟运算符的情况
- 词法合法性:连续数字拼接为一个多位数操作数,禁止两个数字仅用空格分隔(缺运算符)、禁止出现非数字字符和数字拼接的非法token
- 语法顺序:用状态位标记当前位置期望接收的token类型,要么期望操作数(可以是数字、左括号、一元正负号),要么期望运算符(可以是二元运算符、右括号),不允许出现连续二元运算符、运算符在表达式首尾、运算符直接邻接括号等顺序错误
- 运算前置校验:可以提前拦截除零、取模操作数非整数这类运行时错误
完整可运行校验代码
#include <string> #include <stack> #include <cctype> enum ErrorCode { SUCCESS = 0, INVALID_CHAR = -1, PAREN_MISMATCH = -2, SYNTAX_ORDER_ERROR = -3, INVALID_TOKEN = -4, INVALID_OPERATION = -5 }; int32_t check_error(const std::string& str) { std::stack<char> paren_stack; // 初始状态期望读取操作数 bool expect_operand = true; bool last_is_space = false; size_t len = str.length(); for (size_t i = 0; i < len; ++i) { char c = str[i]; if (isspace(c)) { last_is_space = true; continue; } // 非法字符校验 if (!isdigit(c) && c != '+' && c != '-' && c != '*' && c != '/' && c != '%' && c != '^' && c != '(' && c != ')') { return INVALID_CHAR; } // 数字处理逻辑 if (isdigit(c)) { if (!expect_operand) { return SYNTAX_ORDER_ERROR; } // 检查是否为空格分隔的两个独立数字(缺运算符) bool prev_is_digit = false; for (int j = i-1; j >=0; --j) { if (isspace(str[j])) continue; prev_is_digit = isdigit(str[j]); break; } if (last_is_space && prev_is_digit) { return INVALID_TOKEN; } // 跳过整个连续数字段,支持任意长度多位数 while (i < len && isdigit(str[i])) { ++i; } --i; // 回退到数字段最后一位,避免循环跳过后续字符 expect_operand = false; last_is_space = false; continue; } // 左括号处理逻辑 if (c == '(') { if (!expect_operand) { return SYNTAX_ORDER_ERROR; } paren_stack.push(c); expect_operand = true; last_is_space = false; continue; } // 右括号处理逻辑 if (c == ')') { if (expect_operand || paren_stack.empty()) { return PAREN_MISMATCH; } paren_stack.pop(); expect_operand = false; last_is_space = false; continue; } // 运算符处理逻辑 bool is_unary = (c == '+' || c == '-') && expect_operand; // 不存在一元的乘除模幂运算 if (!is_unary && expect_operand) { return SYNTAX_ORDER_ERROR; } if ((c == '*' || c == '/' || c == '%' || c == '^') && is_unary) { return SYNTAX_ORDER_ERROR; } expect_operand = true; last_is_space = false; } // 遍历完成后的最终校验 if (expect_operand) { return SYNTAX_ORDER_ERROR; } if (!paren_stack.empty()) { return PAREN_MISMATCH; } return SUCCESS; }
和原有逻辑的差异说明
- 去掉了首尾必须为括号的错误判断,支持无括号的普通中缀表达式
- 不再用固定位置偏移判断邻接字符,通过逐字符遍历+状态标记适配任意长度的数字、任意数量的合法空格
- 新增栈结构实现括号完全匹配校验,支持多层嵌套括号的合法性判断
- 新增一元正负号识别,支持
-3+5、( -2 * 4 )这类带一元运算符的合法表达式 - 覆盖所有顺序错误场景:连续运算符、操作数缺省、括号邻接非法字符、表达式首尾为运算符等
内容的提问来源于stack exchange,提问作者Minh_Peter
相关产品推荐
相关产品推荐

