2017-04-17 145 views
0

我想用正则表达式来验证一个字符串。它应该允许字符串和booleaen运算符(如(@string1 OR))之间有空格,但不允许在(string 1)之类的字符串之间使用空格。允许其他布尔逻辑是:可能的有效和无效投入布尔逻辑的正则表达式

(A AND B) AND (NOT C) 
(A OR B) AND (NOT C) 
(A AND B) 
(A OR B) 
(NOT C) 

例子如下。

有效期:

(@string1 OR @string2) AND (NOT @string3) 
(@string-1 AND @string.2) AND (NOT @string_3) 
(@string1 OR @string2 OR @string4) AND (NOT @string3 AND NOT @string5) 
(@string1 OR @string2 OR @string4) 
(@string1 AND @string2 AND @string4) 
(NOT @string1 AND NOT @string2 AND NOT @string4) 
(NOT @string1 AND NOT @string2) 

无效:

() 
(string 1 OR @str ing2) AND (NOT @tag3) 
(@string 1 OR @tag 2) AND (NOT @string 3) 
(@string1 @string2) (NOT @string3) 
(@string1 OR @string12) AND (@string3) 
(@string1 AND NOT @string2) 

是更好地解析字符串,然后有多个正则表达式核实没有空格的,或者可以在正则表达式写检查整个字符串?

+0

这些查询可以嵌套'(...)',正确吗? –

+0

此外,什么阻止用户: - 不是,第二个NOT是一个字符串?我想我问的是,你怎么知道什么是和不是一个字符串? – grail

+0

@WiktorStribiżew是的,这是正确的。 –

回答

0

你需要递归或循环,并且一个堆栈解析正确和正则表达式将是非常困难的,尽管无法验证。

0

这种复杂的验证最好用语法分析器来解决。

只是为了让你开始,这里是一个(不完整的)在parslet中的解决方案。正如你所看到的,你从基元构建起来并构建越来越复杂的结构。

require 'parslet' 

class Boolean < Parslet::Parser 
    rule(:space) { match[" "].repeat(1) } 
    rule(:space?) { space.maybe } 

    rule(:lparen) { str("(") >> space? } 
    rule(:rparen) { str(")") >> space? } 

    rule(:and_operator) { str("AND") >> space? } 
    rule(:or_operator) { str("OR") >> space? } 
    rule(:not_operator) { str("NOT") >> space? } 

    rule(:token) { str("@") >> match["a-z0-9"].repeat >> space? } 

    # The primary rule deals with parentheses. 
    rule(:primary) { lparen >> expression >> rparen | token } 

    rule(:and_expression) { primary >> and_operator >> primary } 
    rule(:or_expression) { primary >> or_operator >> primary } 
    rule(:not_expression) { not_operator >> primary } 

    rule(:expression) { or_expression | and_expression | not_expression | primary } 

    root(:expression) 
end 

你可以用这个小帮手方法测试字符串:

def parse(str) 
    exp = Boolean.new 
    exp.parse(str) 
    puts "Valid!" 
rescue Parslet::ParseFailed => failure 
    puts failure.parse_failure_cause.ascii_tree 
end 

parse("@string AND (@string2 OR @string3)") 
#=> Valid! 
parse("(string1 AND @string2)") 
#=> Expected one of [OR_EXPRESSION, AND_EXPRESSION, NOT_EXPRESSION, PRIMARY] at line 1 char 1. 
# ... 
# - Failed to match sequence ('@' [a-z0-9]{0, } SPACE?) at line 1 char 2. 
#  - Expected "@", but got "s" at line 1 char 2.