使用Sprache从标识符解析枚举?

时间:2015-09-21 16:08:22

标签: c# parsing enums dsl sprache

我开始使用Sprache来解析数学表达式的特定于域的语言。我知道我可以使用以下内容解析标识符:

    static readonly Parser<string> Identifier = 
        from leading in Parse.WhiteSpace.Many()
        from first in Parse.Letter.Once()
        from rest in Parse.LetterOrDigit.Many()
        from trailing in Parse.WhiteSpace.Many()
        select new string(first.Concat(rest).ToArray());

由此我想构建一个只有在Identifier令牌是Enum的文本值之一时才能成功的解析器。所以说我有一个名为Dimension的Enum,其值为Dimension.Location和Dimension.Time。我想做

    static readonly Parser<Dimension> DimensionIdentifier = ...

只有在解析的内容是标识符并且标识符的标记字符串是枚举名称之一(&#34;位置&#34;或&#34;时间&#34;)时才会成功分别返回枚举值,Dimension.Location或Dimension.Time。有人可以帮忙解决一个简单的问题吗?谢谢!

2 个答案:

答案 0 :(得分:0)

从这里偷来的非常好的解决方案...... http://www.codewise-llc.com/blog/2015/8/13/parsing-enum-values-with-sprache

构建一个类型化的助手类,为给定的枚举构建解析器......

public static class EnumParser<T>
{
    public static Parser<T> Create()
    {
        var names = Enum.GetNames(typeof(T));

        var parser = Parse.IgnoreCase(names.First()).Token()
            .Return((T)Enum.Parse(typeof(T), names.First()));

        foreach (var name in names.Skip(1))
        {
            parser = parser.Or(Parse.IgnoreCase(name).Token().Return((T)Enum.Parse(typeof(T), name)));
        }

        return parser;
    }
}

然后你的解析器就是这个......

public static Parser<Dimension> Dimension = EnumParser<Dimension>.Create();

还有一些单元测试(将类名改为你正在使用的,我使用Sprache教程开始)...

 [Test]
        [TestCase("Time", Dimension.Time)]
        [TestCase("Location", Dimension.Location)]
        public void ShouldGetProperEnumValue(string enumValueName, Dimension expected)
        {
            var eValue = QuestionnaireGrammar.Dimension.Parse(enumValueName);
            Assert.AreEqual(expected, eValue);
        }

        [Test]
        [ExpectedException]
        [TestCase("Fredo")]
        public void ShouldFailIfNotInList(string enumValueName)
        {
            var eValue = QuestionnaireGrammar.Dimension.Parse(enumValueName);
        }

有趣的图书馆,很高兴了解它。

好的,相当容易链解析器...

创建了您的身份解析器的副本,并将其称为Identifier2以保持清晰......

  public static readonly Parser<string> Identifier2 =
            from leading in Parse.WhiteSpace.Many()
            from first in Parse.Letter.Once()
            from rest in Parse.LetterOrDigit.Many()
            from trailing in Parse.WhiteSpace.Many()
            select new string(first.Concat(rest).ToArray());

然后添加了一个复合解析器,它获取Identifier2解析器的结果并使用Dimension解析器......

 public  static readonly Parser<Dimension> IdentityDimension =
            from result in Identifier2
            select Dimension.Parse(result);

虽然不确定你要买什么 - 枚举解析器似乎已经完成了标识符解析器所做的一切。

答案 1 :(得分:0)

我使用以下方法:

import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class TurtleClass extends JFrame {

    public static void main(String[] args) 
    {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TurtleClass();
            }
        });
    }

    public TurtleClass()
    {
        JFrame frame = new JFrame("Turtle Graphics");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        GraphicsPanel panel = new GraphicsPanel();

        frame.add(panel);
        frame.pack();
        frame.setVisible(true);

        panel.turnLeft();
        panel.forward(100);
        panel.turnRight();
        panel.penDown();
        panel.forward(400);
    }
}

它类似于dbugger's answer,因为它仍然基于public static Parser<TEnum> ParseEnum() { return Enum.GetValues(typeof(TEnum)) .Cast<TEnum>() .Select(value => Parse.IgnoreCase(Enum.GetName(typeof(TEnum), value)).Return(value)) .Aggregate((x, y) => x.Or(y)); } ,但是以更实用的方式编写。