C#:将字符串转换为已知操作的序列

时间:2012-08-29 18:58:23

标签: c# string parsing lexer

我想将A中给出的一系列扑克牌转换为B格式,以便我可以生成结果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)union,','

我有在B中执行操作的功能,例如Intersect(“AA”,“* s * s”)==“AsAs”,但我需要一种方法从表单A到表单B输入和相关操作,我可以按顺序执行以达到C.

我已经查看了Irony和其他一些词法分析器/解析器解决方案,但它们对于这个问题似乎有些过分。有更简单的解决方案吗?

  • 也许递归地将字符串拆分为一个表示操作的节点的树?
  • 按优先顺序相反的顺序分解字符串并将其推入堆栈?如果是这样的话(大致)如何实施呢?

我试图模仿的一个工作示例是here。您可以找到有关A here语法的更详细说明。

2 个答案:

答案 0 :(得分:2)

你可以解析A来构造一个指令树,然后从叶子开始执行它们(因为我假设你想先执行最里面括号的内容)。对于此解析任务,您可以使用Regexes或其他任何您想要的。在我的脑海中,我认为您可以首先查找括号和运算符符号以找出树结构,然后使用实际的基本指令和每个与运算符的结点填充每个叶子。

存储A的数据结构可以由实现接口Expression的对象(称为IOperand)组成;每个Expression应该有三个字段:

  1. 字段Operator,它是enum Operations {Union, Intersection, SetDiff}的一个实例,或者只是一个字符串,具体取决于您的喜好。
  2. 两个字段Operand1Operand2,可以是“Ah”(定义一组卡片)或另一个Expression。因此,它们应声明为IOperand
  3. 的实例

    你持有一套卡片的班级,比如“啊”,也应该实现这个IOperand。接口IOperand本身不需要做任何事情。

    为了将每个给定指令与操作匹配,您可以使用简单的开关,或者Dictionary string(或enum)到delegate IOperand SetOp(IOperand, IOperand);,然后使用(匿名)函数填充Dictionary(包含B的说明。)

    Dictionary的情况下,您可以简单地执行instructionList[thisExpression.Operation](thisExpression);(这可能会更优雅地完成以避免引用thisExpression两次)以及相应的C#转换字符串输入将被执行。

    概念证明

    我已经制作了一个基本实现和一个控制台应用来演示这里的用法:https://bitbucket.org/Superbest/lexer

    如果你成功完成了整个练习并保持完整性(计算机会将你用作代理解析和操作库,那么祝你好运)那么最后一步应该要求你评估一个等于{的表达式{1}}然后打印刚刚输入的内容。 (当第一次运行时,您可能希望遵守程序的指令。我怀疑打破代码并获得大量异常非常容易,如果您试图考虑无效的事情,那么就会非常困惑。输入。)

    如果您按原样运行代码,请尝试以下答案序列(,= Enter):

    C

    您的输出将是:

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

    您应该能够简单地更新标记为过时且具有工作程序的方法的主体。

    如果您想添加更多二进制操作,请参阅gamma 正文中的TODO。从我已经做过的三个操作中可以看出适当的语法;实际上,代码仅支持二进制操作。如果您的方法使用字符串,则可以使用Simplification.Simplification()字段。

答案 1 :(得分:1)

我想出了这个解决方案(使用Superbest的答案中的树形思想)。任何关于你会改变的事情的评论都将不胜感激!

  • 输入:“AsQs,(JJ!ss:xy),(AA:xy!ss)”
  • 漂亮的打印输出:AsQs union(((JJ less ss)交点xy)union((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; }
    }
}