2012-08-29 11 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; } 
    } 
}