有趣的问题。phant0m 的回答很有教育意义!(如果您了解解析器,应该使用它)。
如果您只想使用正则表达式来执行此操作,则以下解决方案使用 JavaScript 正确验证任意嵌套的逻辑语句。
规则/假设:
- 有效语句仅由数字、括号、空格、
AND
逻辑运算符和OR
逻辑运算符组成。
- 该语句必须包含至少两个“标记”,由逻辑运算符分隔,其中每个标记要么是“数字”,要么是“带括号的单位”。
- “数字”标记是一个数字整数,具有一个或多个十进制数字,前面紧接可选符号(
+
或-
)。
- “带括号的单元”标记是两个或多个标记,由逻辑运算符分隔,包含在匹配的开括号和右括号中。
- 整个语句可能包含两个以上的标记,但所有标记必须由相同的单个运算符分隔;要么
AND
要么OR
。
- 每个带括号的单元可能包含两个以上的标记,但所有标记必须由相同的单个运算符分隔;要么
AND
要么OR
。
- 在任何元素(括号、数字和逻辑运算符)之间可以使用任意数量的空格,但在数字和逻辑运算符之间至少需要一个空格。
- 和逻辑运算
AND
符OR
不区分大小写。
有效逻辑语句的示例:
"1 AND 2"
"1 AND 2 AND 3"
"1 OR 2"
"-10 AND -20"
"100 AND +200 AND -300"
"1 AND (2 OR 3)"
"1 AND (2 OR 3) AND 4"
"1 OR ((2 AND 3 AND 4) OR (5 OR 6 OR 7))"
"( 1 and 2 ) AND (1 AND 2)"
无效逻辑语句的示例:
"1x" // Invalid character.
"1 AND" // Missing token.
"1 AND 2 OR 3" // Mixed logical operators.
"(1" // Unbalanced parens.
"(((1 AND 2)))" // Too many parens.
"(1 AND) (2)" // Missing token.
"1" // Missing logical operator and second number
"1OR2OR3OR4" // Missing spaces between numbers and operators.
"(1) AND (2)" // Invalid parentheses.
正则表达式解决方案:
这个问题需要匹配嵌套的括号结构,并且 JavaScript 正则表达式引擎不支持递归表达式,因此无法使用单个正则表达式一次性解决这个问题。但是,可以将问题简化为两个部分,每个部分都可以使用单个 JavaScript 正则表达式来解决。第一个正则表达式匹配最里面的括号单元,第二个验证简化的逻辑语句(没有括号)。
正则表达式 #1:匹配最里面的括号单元。
以下正则表达式匹配一个带括号的单元,该单元由两个或多个数字标记组成,其中数字全部由数字和逻辑运算符之间的一个AND
或OR
至少一个空格分隔。正则表达式经过全面注释和格式化,以便在 PHP 自由间距模式语法中易于阅读:
$re_paren = '/
# Match innermost "parenthesized unit".
\( # Start of innermost paren group.
\s* # Optional whitespace.
[+-]?\d+ # First number token (required).
(?: # ANDs or ORs (required).
(?: # Either multiple AND separated values.
\s+ # Required whitespace.
AND # Logical operator.
\s+ # Required whitespace.
[+-]?\d+ # Additional number.
)+ # multiple AND separated values.
| (?: # Or multiple OR separated values.
\s+ # Required whitespace.
OR # Logical operator.
\s+ # Required whitespace.
[+-]?\d+ # Additional number token.
)+ # multiple OR separated values.
) # ANDs or ORs (required).
\s* # Optional whitespace.
\) # End of innermost paren group.
/ix';
正则表达式 #2:验证简化的逻辑语句。
这是一个(除了边界锚点几乎相同)正则表达式,它验证简化的逻辑语句(只有数字和逻辑运算符,没有括号)。这是注释的自由间距模式(PHP)语法:
$re_valid = '/
# Validate simple logical statement (no parens).
^ # Anchor to start of string.
\s* # Optional whitespace.
[+-]?\d+ # First number token (required).
(?: # ANDs or ORs (required).
(?: # Either multiple AND separated values.
\s+ # Required whitespace.
AND # Logical operator.
\s+ # Required whitespace.
[+-]?\d+ # Additional number.
)+ # multiple AND separated values.
| (?: # Or multiple OR separated values.
\s+ # Required whitespace.
OR # Logical operator.
\s+ # Required whitespace.
[+-]?\d+ # Additional number token.
)+ # multiple OR separated values.
) # ANDs or ORs (required).
\s* # Optional whitespace.
$ # Anchor to end of string.
/ix';
请注意,除了边界锚点之外,这两个正则表达式是相同的。
JavaScript 解决方案:
以下经过测试的 JavaScript 函数使用上述两个正则表达式来解决问题:
function isValidLogicalStatement(text) {
var re_paren = /\(\s*[+-]?\d+(?:(?:\s+AND\s+[+-]?\d+)+|(?:\s+OR\s+[+-]?\d+)+)\s*\)/ig;
var re_valid = /^\s*[+-]?\d+(?:(?:\s+AND\s+[+-]?\d+)+|(?:\s+OR\s+[+-]?\d+)+)\s*$/ig;
// Iterate from the inside out.
while (text.search(re_paren) !== -1) {
// Replace innermost parenthesized units with integer.
text = text.replace(re_paren, "0");
}
if (text.search(re_valid) === 0) return true;
return false;
}
该函数使用迭代技术首先匹配和替换最里面的括号单元,用单个数字标记替换每个单元,然后检查结果语句(无括号)是否有效。
附录:2012-11-06
在对此答案的评论中,OP 现在说数字和运算符之间必须有空格,并且数字或带括号的单位可能不会独立存在。考虑到这些附加要求,我更新了上面的答案。