2017-04-17 493 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.