使用Sprache从标识符解析枚举

本文关键字:枚举 标识符 Sprache 使用 | 更新日期: 2023-09-27 18:13:42

我开始使用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());

从这里我想构建一个解析器,只有当标识符令牌是Enum的文本值之一时才成功。假设我有一个名为Dimension的Enum,它的值是Dimension。位置和维度,时间。我想让

    static readonly Parser<Dimension> DimensionIdentifier = ...

只有在被解析的内容是标识符并且标识符的令牌字符串是枚举名称之一("Location"或"Time")时才成功,并且返回枚举值Dimension。位置或尺寸。分别的时间。有人能帮我解决一个很简单的问题吗?谢谢!

使用Sprache从标识符解析枚举

我使用以下方法:

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));
}

它类似于调试者的答案,因为它仍然基于Parse.Or,但以更实用的风格编写。

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

构建一个类型化的帮助类,为给定的enum构建解析器…

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);

虽然不确定你在买什么——enum解析器似乎已经做了标识符解析器所做的一切。