2012-08-29 10 views
0

的我想的給定在一個打牌的字符串轉換爲B型,這樣我可以產生一個結果C.C#轉換字符串到序列已知的操作

A: "(AK,AQ,(A2:*h*h)):*s*s!AsQs,(JJ:*s*h)" 
B: (((AsKs union AsQs union (A2 intersect hand with two hearts)) intersect hand with two spades) less AsQs) union (JJ intersect hand with one spade one heart) 
C: AsKs,JsJh 

操作的優先級是

  • 1)括號 '()'
  • 2)相交併小於(左結合), ':'
  • 3)結合, ''

我必須執行在B的操作的功能,例如相交( 「AA」, 「* S * S」)== 「ASAS」,但我需要一種方法從表單A獲得輸入和相關操作的表單B,我可以按順序執行以獲得C。

我已經看過Irony和其他一些詞法分析器/解析器解決方案,但它們似乎是這個問題有點矯枉過正。有一個更簡單的解決方案嗎?

  • 也許遞歸地將字符串拆分成一棵樹,其中的節點表示操作?
  • 按照相反的順序分解字符串並將其推入堆棧?如果是這樣(大體上)如何實現?

我試圖效仿的一個工作例子是here。您可以找到A here的語法更詳細的說明。

+0

Downvoter,照顧評論? –

+0

您能否提供A符合的語法規範以及它是如何翻譯爲B的? – Superbest

+1

我寫了一個名爲TokenIcer的詞法分析器,它可能正是您的項目所需要的。檢查[項目在這裏](http://www.codeproject.com/Articles/220042/Easily-Create-Your-Own-Parser)。它將以您希望的任何.NET語言爲您創建代碼!您只需將規則定義爲RegEx表達式,並自動爲整個詞法分析器創建源代碼。另外,我寫了一個使用TokenIcer的數學解析器。有了這個,你可以看到如何解析表達式。看看它[這裏](http://www.codeproject.com/Articles/274093/Math-Parser-NET) – Icemanind

回答

2

你可以解析A來構造指令樹,然後從樹葉開始執行它們(因爲我假設你想先執行最內層括號的內容)。對於這個解析任務,你可以使用正則表達式,或其他任何你想要的。關於我的頭頂,我認爲你可以先查找圓括號和運算符符號來找出樹結構,然後用實際的基本指令和與操作符的每個交點填充每個葉子。

數據結構存儲A可以由實現接口IOperand的對象(稱爲它們Expression)組成;每個Expression應該有三個領域:

  1. Operator這是enum Operations {Union, Intersection, SetDiff}一個實例,或只是一個字符串,這取決於你喜歡。
  2. 兩個字段Operand1Operand2,它們可以是「Ah」(定義一組卡片)或另一個Expression。因此,應將其聲明爲IOperand的實例。

你的班級持有一套卡,如「啊」,也應該實現這個IOperand。界面IOperand本身實際上不需要做任何事情。

對於每一個給定的指令匹配的操作,您可以使用一個簡單的開關,或者的string(或enum)到delegate IOperand SetOp(IOperand, IOperand);一個Dictionary,然後填充您Dictionary用(匿名)功能(將包含的說明B)。

Dictionary情況下,您只需將能夠做到instructionList[thisExpression.Operation](thisExpression);(這大概可以做到更優雅一點,以避免引用thisExpression兩次)和字符串輸入適當的C#轉換將被執行。概念

證明

我已經做了基本的實現和控制檯應用程序演示使用這裏:https://bitbucket.org/Superbest/lexer

如果你在整個鍛鍊你的理智完好(電腦會進展成功使用你作爲代理解析和操作庫,所以祝你好運),那麼最後一步應該要求你評估一個等於C的表達式,然後打印你剛纔輸入的內容。 (第一次運行時,您可能想要遵守程序指令,我懷疑破解代碼和獲取大量例外非常容易,如果您想要考慮發生了什麼情況,您會非常困惑自己。輸入)

如果您正在爲運行這些代碼,嘗試回答以下序列(=輸入):

n, y, 2, n, n, n, y, 2, n, n, y, n, y, 2, n, n, n, n, alpha, beta, gamma 

你的輸出將是:

gamma 

你應該能夠簡單地更新標記爲過時的方法的主體並進行工作ng程序。

如果您希望添加更多二進制操作,請參閱Simplification.Simplification()正文中的TODO。通過查看我已經完成的三項操作,適當的語法將會很明顯;實際上,代碼僅支持二進制操作。如果您的方法使用字符串,則可以使用SimplifiedOperand.Symbol字段。

1

我想出了這個作爲解決方案(使用Superbest的答案中的樹的想法)。任何意見你會改變的東西將不勝感激!

  • 輸入: 「AsQs,(JJ SS:XY),(AA:XY SS)」
  • 漂亮的打印輸出:AsQs聯盟(((JJ少SS)相交XY)聯盟((AA路口XY)少SS))
 

public class Node 

{ 
    private string mStr; 
    private string mOperation; 
    private List mChildren = new List(); 
    //private Collection mCollection = new Collection(); 

    public Node(string input) 
    { 
     mStr = Regex.Replace(input, @"^\(([^\(\)]*)\)$", "$1"); 

     Init(); 
    } 

    private void Init() 
    { 
     Split(mStr); 

     return; 
    } 

    public Collection GenerateHands() 
    { 
     Collection collection = new Collection(); 

     if (Children == 0) { collection.Add(mStr); } 

     if (Children > 0) 
     { 
      if (mOperation == "union") { collection = mChildren.ElementAt(0).GenerateHands().Union(mChildren.ElementAt(1).GenerateHands()); } 
      if (mOperation == "intersect") { collection = mChildren.ElementAt(0).GenerateHands().Intersect(mChildren.ElementAt(1).GenerateHands()); } 
      if (mOperation == "less") { collection = mChildren.ElementAt(0).GenerateHands().Less(mChildren.ElementAt(1).GenerateHands()); } 
     } 

     return collection; 
    } 

    public string PrettyPrint() 
    { 
     string print = ""; 

     if (Children == 0) { print += mStr; } 

     if (Children > 0) 
     { 
      if (mChildren.ElementAt(0).Children > 0) { print += "("; } 
      print += mChildren.ElementAt(0).PrettyPrint(); 
      if (mChildren.ElementAt(0).Children > 0) { print += ")"; } 
      if (Children > 0) { print += " " + mOperation + " "; } 
      if (mChildren.ElementAt(1).Children > 0) { print += "("; } 
      print += mChildren.ElementAt(1).PrettyPrint(); 
      if (mChildren.ElementAt(1).Children > 0) { print += ")"; } 
     } 

     return print; 
    } 

    private void Split(string s) 
    { 
     // WARNING: Either could pass a,aa or a:aa 

     // WARNING: This can hand down a 0 length string if ',' is at beginning or end of s. 
     if (CommaOutsideBrackets(s) >= 0) 
     { 
      mChildren.Add(new Node(s.Substring(0, CommaOutsideBrackets(s)))); 
      mChildren.Add(new Node(s.Substring(CommaOutsideBrackets(s) + 1, s.Count() - CommaOutsideBrackets(s) - 1))); 

      mOperation = "union"; 
     } 

     // WARNING: This could throw negative if for example (aaaa)bb 
     else if (OperatorOutsideBrackets(s) >= 0) 
     { 
      mChildren.Add(new Node(s.Substring(0, OperatorOutsideBrackets(s)))); 
      mChildren.Add(new Node(s.Substring(OperatorOutsideBrackets(s) + 1, s.Count() - OperatorOutsideBrackets(s) - 1))); 

      if (s[OperatorOutsideBrackets(s)] == '!') { mOperation = "less"; } 
      if (s[OperatorOutsideBrackets(s)] == ':') { mOperation = "intersection"; } 
     } 

     // We must be done? 
     else 
     { 
     } 
    } 

    private int CommaOutsideBrackets(string s) 
    { 
     int countRound = 0, countSquare = 0; 

     for (int i = 0; i = 0; i--) 
     { 
      if (s[i] == '!' || s[i] == ':') { return i; } 
     } 

     return -1; 
    } 

    public string Str 
    { 
     get { return mStr; } 
    } 

    public int Children 
    { 
     get { return mChildren.Count; } 
    } 
}