2012-09-17 8 views
6

今後のプロジェクトの一環として、特定のドメインオブジェクトをタグやタグの組み合わせに適用できるように設定したいと考えています。人間が入力した論理プロパティを解析する方法。これと(それか他の)?

私は次のように、ユーザーが判読可能な方法でこれらの組み合わせを入力して持ってできるようにしたいと思います:

  • タグ-Aおよび(タグ-Bまたはタグ-C) - >適用されますタグ-a +タグ-bまたはタグ-a +タグ-c
  • タグ-dまたは(タグ-eおよびタグ-f)→タグ-dまたはタグ-e +タグ-fに適用

入力されたテキストの1つの文字列からこの種のロジック解析を行うツールセットが存在しますか?タグをシーンの背後にある区別({}、[]など)で定義することで、より簡単に解析することができます。

ユーザーが各特定の組み合わせを入力する必要なしに、人間が読めるテキストをこれらの異なる組み合わせの組み合わせに解析することが最も良い方法であるかどうかは疑問です。

ありがとうございます!

答えて

7

典型的には、これは、2つのステップを伴う:字句字句解析の略)と解析を。

最初の手順では、入力文字列をトークンと呼ばれる語彙項目のシーケンスに変換します。この目的のためには、例えば、トークンの種類ごとに列挙型を宣言することがあります

public enum TokenType 
{ 
    OpenParenthesis, 
    CloseParenthesis, 
    And, 
    Or, 
    Tag 
} 

とトークンのクラス:

sealed class Token 
{ 
    public TokenType Type { get; private set; } 
    public string Item { get; private set; } 
    public Token(TokenType type, string item) { Type = type; Item = item; } 
} 

は今、あなたは入力文字列をオンにするアルゴリズムを記述し、例えばtag-a and (tag-b or tag-c)を、Tokenのインスタンスに変換します。正規表現を使用してさまざまな項目を認識できます。たとえば、@"\s*\(\s*"は空白を認識するための正規表現になります。完成したシーケンスは次のようになります:

  • new Token(TokenType.Tag, "tag-a")
  • new Token(TokenType.And, null)
  • new Token(TokenType.OpenParenthesis, null)
  • new Token(TokenType.Tag, "tag-b")
  • new Token(TokenType.Or, null)
  • new Token(TokenType.Tag, "tag-c")
  • new Token(TokenType.CloseParenthesis, null)

このシーケンスを取得したら、パーサーを実行する必要があります。このような式の解析には多くの戦略があります。最初はrecursive descent parserをお勧めします。

あなたは、もちろん、解析ツリーを含むようにいくつかのクラスが必要になります。これがあることを

public static Node ParseExpression(Token[] tok) 
{ 
    int i = 0; 
    return parseExpressionBoolOr(tok, ref i); 
} 
private static Node parseExpressionBoolOr(Token[] tok, ref int i) 
{ 
    var left = parseExpressionBoolAnd(tok, ref i); 
    while (tok[i].Type == TokenType.Or) 
    { 
     i++; 
     var right = parseExpressionBoolAnd(tok, ref i); 
     left = new BooleanNode(BooleanOperator.Or, left, right); 
    } 
    return left; 
} 
private static Node parseExpressionBoolAnd(Token[] tok, ref int i) 
{ 
    var left = parseExpressionPrimary(tok, ref i); 
    while (tok[i].Type == TokenType.And) 
    { 
     i++; 
     var right = parseExpressionPrimary(tok, ref i); 
     left = new BooleanNode(BooleanOperator.And, left, right); 
    } 
    return left; 
} 
private static Node parseExpressionPrimary(Token[] tok, ref int i) 
{ 
    if (tok[i].Type == TokenType.OpenParenthesis) 
    { 
     i++; 
     var node = parseExpressionBoolOr(tok, ref i); 
     if (tok[i].Type != TokenType.CloseParenthesis) 
      throw new InvalidOperationException(); // or customised parse exception 
     return node; 
    } 
    else if (tok[i].Type == TokenType.Tag) 
    { 
     var node = new TagNode(tok[i].Item); 
     i++; 
     return node; 
    } 
    else 
     throw new InvalidOperationException(); // or customised parse exception 
} 

注:その後、

abstract class Node { } 
enum BooleanOperator { And, Or } 
sealed class BooleanNode : Node 
{ 
    public BooleanOperator Operator { get; private set; } 
    public Node Left { get; private set; } 
    public Node Right { get; private set; } 
    public BooleanNode(BooleanOperator op, Node left, Node right) 
    { 
     Operator = op; 
     Left = left; 
     Right = right; 
    } 
} 
sealed class TagNode : Node 
{ 
    public string Tag { get; private set; } 
    public TagNode(string tag) { Tag = tag; } 
} 

そして、再帰下降構文解析は次のようになります。非常に簡単な例です。ただし、これは最大限の柔軟性があります。このアルゴリズムを拡張して、必要な言語を完全に解析することができます。

+0

これはすばらしい詳細な例です。概念とコードの両方で、さまざまな方法で多くのことを教えてくれました。この宝石をありがとう! – SeanKilleen

+0

[プレザント:]](http://meta.stackexchange.com/questions/700) – Timwi

関連する問題