2017-04-17 15 views
0

正規表現を使用して文字列を検証しようとしています。文字列とブール演算子の間の空白は(@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 NOT、2番目のNOTは文字列ですか?私は何を求めているのでしょうか、文字列ではないと文字列ではないことをどのように教えていますか? – grail

+0

@WiktorStribiżewはい、正しいです。 –

答えて

0

再帰やループが必要です。それを正しく解析するにはスタックが必要です。正規表現だけを検証することは不可能ですが、非常に困難です。

0

この種の洗練された検証は、文法パーサで最もよく解決されます。

ここをクリックすると、パースレットの(不完全な)ソリューションが表示されます。ご覧のとおり、プリミティブから構築し、ますます複雑な構造を構築します。

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.