使用 Sprache 从标识符解析枚举?
Using Sprache to parse Enums from identifiers?
我开始使用 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());
据此我想构建一个解析器,只有当标识符标记是枚举的文本值之一时它才会成功。假设我有一个名为 Dimension 的枚举,其值为 Dimension.Location 和 Dimension.Time。我要制作
static readonly Parser<Dimension> DimensionIdentifier = ...
只有当被解析的是标识符并且标识符的标记字符串是枚举名称之一("Location" 或 "Time")时才会成功,并且 returns 枚举值,分别为 Dimension.Location 或 Dimension.Time。有人可以帮助解决一个可能很简单的问题吗?谢谢!
从这里偷来的非常好的解决方案...
http://www.codewise-llc.com/blog/2015/8/13/parsing-enum-values-with-sprache
构建一个类型化的帮助程序class来为给定的枚举构建解析器...
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();
和一些单元测试(将 class 名称更改为您正在使用的任何名称,我使用 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 解析器的结果并使用维度解析器...
public static readonly Parser<Dimension> IdentityDimension =
from result in Identifier2
select Dimension.Parse(result);
虽然不确定您购买的是什么 -- 枚举解析器似乎已经完成了标识符解析器所做的一切。
我使用以下方法:
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
,但以更实用的风格编写。
我开始使用 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());
据此我想构建一个解析器,只有当标识符标记是枚举的文本值之一时它才会成功。假设我有一个名为 Dimension 的枚举,其值为 Dimension.Location 和 Dimension.Time。我要制作
static readonly Parser<Dimension> DimensionIdentifier = ...
只有当被解析的是标识符并且标识符的标记字符串是枚举名称之一("Location" 或 "Time")时才会成功,并且 returns 枚举值,分别为 Dimension.Location 或 Dimension.Time。有人可以帮助解决一个可能很简单的问题吗?谢谢!
从这里偷来的非常好的解决方案... http://www.codewise-llc.com/blog/2015/8/13/parsing-enum-values-with-sprache
构建一个类型化的帮助程序class来为给定的枚举构建解析器...
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();
和一些单元测试(将 class 名称更改为您正在使用的任何名称,我使用 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 解析器的结果并使用维度解析器...
public static readonly Parser<Dimension> IdentityDimension =
from result in Identifier2
select Dimension.Parse(result);
虽然不确定您购买的是什么 -- 枚举解析器似乎已经完成了标识符解析器所做的一切。
我使用以下方法:
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
,但以更实用的风格编写。