如何编写验证合取范式(CNF)的C++正则表达式?
正确匹配合取范式(CNF)的正则表达式及C++实现
首先,你的原始正则表达式出现regex_error主要是因为结构逻辑混乱和字符匹配错误,比如错误地用了字符类[v(会匹配[或v而不是你需要的析取符∨),同时没有严格遵循CNF的结构规则。
先明确我们要匹配的CNF严格规则(根据你的定义)
- 所有子句必须被
()包裹,子句内部是合法变量用∨连接(可以是单个变量,比如(P)) - 子句之间只能用
&连接,不能有其他运算符 - 合法变量仅限:
P, Q, R, S, ~P, ~Q, ~R, ~S
正确的正则表达式(无空格)
我们可以把规则拆解成几个部分,最终的正则(正则语法)是:
^(\((~?[PQRS])(∨~?[PQRS])*\))(&\((~?[PQRS])(∨~?[PQRS])*\))*$
正则各部分解释
^和$:确保整个字符串完全匹配,避免部分匹配(比如字符串末尾多了无关字符也会被误判)\((~?[PQRS])(∨~?[PQRS])*\):匹配单个合法子句\(和\):匹配子句的括号(正则里需要转义)~?[PQRS]:匹配单个合法变量(~可选,后跟P/Q/R/S中的一个)(∨~?[PQRS])*:匹配0个或多个“析取符+合法变量”的组合,支持子句里有多个变量
(&\((~?[PQRS])(∨~?[PQRS])*\))*:匹配0个或多个“合取符+子句”的组合,实现多个子句的连接
C++中的正确实现(避免转义麻烦)
在C++中,推荐用原始字符串字面量(R"(...)")来写正则,避免双重转义的麻烦。同时要注意∨的编码(如果你的环境不支持直接输入∨,可以用Unicode转义\u2228代替):
#include <iostream> #include <regex> #include <string> #include <vector> int main() { // 使用原始字符串字面量,避免双重转义;∨可以换成\u2228如果环境不支持直接输入 std::regex cnf_regex(R"(^(\((~?[PQRS])(∨~?[PQRS])*\))(&\((~?[PQRS])(∨~?[PQRS])*\))*$)"); // 测试用例集合 std::vector<std::string> test_cases = { "(P∨Q)&(Q∨R∨S)&(R∨Q)", // 你的示例,合法 "(P)", // 单个子句,合法 "(~P∨Q)&(~R)", // 带否定的变量,合法 "P∨Q", // 未包裹成子句,不合法 "(P&Q)∨R", // 子句内部用了&,不合法 "(X∨P)", // 非法变量X,不合法 "(P∨~Q)&(R∨S)" // 合法 }; // 遍历测试 for (const auto& expr : test_cases) { bool is_valid = std::regex_match(expr, cnf_regex); std::cout << "表达式: " << expr << " → " << (is_valid ? "符合CNF" : "不符合CNF") << std::endl; } return 0; }
为什么你的原始正则会报错?
- 错误使用字符类
[v:这会匹配[或v,完全不是你需要的析取符∨ - 结构逻辑错误:
[(~?[PQRS]{1}[v~?[PQRS]{1}]*)&]*会匹配任意顺序的子句片段和&,不符合CNF“子句必须用&依次连接”的规则 - 没有用
^和$:会导致部分匹配,比如字符串中间的一段符合规则就会被误判 - 没有强制子句的括号:允许了未包裹的变量组合,不符合CNF定义
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

