6

我想在 javascript 中创建正则表达式,它将检查有效的条件字符串,例如

-1 OR (1 AND 2) AND 1

-1 OR (1 AND 2)

-1 OR 2

-1 OR 1 OR 1

-1 AND 1 AND 1

字符串不应包含“AND”和“OR”。例如-1 OR 2 AND 3 无效。- 它应该是(1 OR 2) AND 3 or 1 or (2 AND 3)

我尝试了以下正则表达式。它适用于大多数情况,但无法检查上述情况。

/^(\s*\(\d+\s(AND|OR)\s\d+\)|\s*\d+)((\s*(AND|OR)\s*)(\(\d+\s(AND|OR)\s\d+\)|\s*\d+))*$/

谁能帮我解决上述问题。

4

2 回答 2

5

忘记正则表达式,他们做不到。

解析器生成器来救援

使用解析器生成器,您可以创建可理解和可维护的语法。

这是一个带有在线演示的 JavaScript解析器生成器。

语法

据我了解,您不希望ANDand之间有任何隐含的优先规则OR

以下是它认为有效的示例:

-1 OR 2 OR (2 AND 2 AND (2 OR (6 AND -2 AND (6 OR 2) AND (6 OR 2)) OR 2 OR 2))

目前,语法需要/支持

  • “无限”嵌套
  • 带括号的显式优先级控制AND/OR
  • (多)文字的否定
  • 操作数和运算符之间的空格

语法可以很容易地更改

  • 允许任意空格
  • 文字的可选否定,而不是可能的多重否定
  • 任何子表达式的否定

如果您想要更深入的解释或无法弄清楚如何根据自己的喜好进行调整,只需发表评论即可。

这是您的语法,只需将其粘贴到在线生成器中,然后单击Download parser

start
  = formula

formula
 = ors
 / ands
 / literal
 / parens_formula

parens_formula
 = "(" formula ")"

ors
 = operand (whitespace "OR" whitespace  operand)+

ands
 =  operand (whitespace "AND" whitespace operand)+

whitespace
 = " "+

operand
 = literal
 / parens_formula

literal
 = integer
 / "-" literal

integer "integer"
  = digits:[0-9]+ { return parseInt(digits.join(""), 10); }
于 2012-11-03T12:51:36.570 回答
4

有趣的问题。phant0m 的回答很有教育意义!(如果您了解解析器,应该使用它)。

如果您只想使用正则表达式来执行此操作,则以下解决方案使用 JavaScript 正确验证任意嵌套的逻辑语句。

规则/假设:

  • 有效语句仅由数字、括号、空格、AND逻辑运算符和OR逻辑运算符组成。
  • 该语句必须包含至少两个“标记”,由逻辑运算符分隔,其中每个标记要么是“数字”,要么是“带括号的单位”。
  • “数字”标记是一个数字整数,具有一个或多个十进制数字,前面紧接可选符号(+-)。
  • “带括号的单元”标记是两个或多个标记,由逻辑运算符分隔,包含在匹配的开括号和右括号中。
  • 整个语句可能包含两个以上的标记,但所有标记必须由相同的单个运算符分隔;要么AND要么OR
  • 每个带括号的单元可能包含两个以上的标记,但所有标记必须由相同的单个运算符分隔;要么AND要么OR
  • 在任何元素(括号、数字和逻辑运算符)之间可以使用任意数量的空格,但在数字和逻辑运算符之间至少需要一个空格。
  • 和逻辑运算ANDOR不区分大小写。

有效逻辑语句的示例:

"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:匹配最里面的括号单元。

以下正则表达式匹配一个带括号的单元,该单元由两个或多个数字标记组成,其中数字全部由数字和逻辑运算符之间的一个ANDOR至少一个空格分隔。正则表达式经过全面注释和格式化,以便在 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 现在说数字和运算符之间必须有空格,并且数字或带括号的单位可能不会独立存在。考虑到这些附加要求,我更新了上面的答案。

于 2012-11-03T19:20:06.610 回答