我正在研究一个字符串解析器,它将读取一个短语或句子并解析它以获得日程/时间信息。例如,输入可能包含短语
“每天两次”
或
“星期一,星期三和星期五”
目标是创建一个模板,在给定开始日期和结束日期时,该模板可以转换为DateTimes
列表。我已考虑将此模板存储为Func<DateTime, bool>
:
前一个例子可能被解释为(d => d.TimeOfDay == TimeSpan.FromHours(8) || d.TimeOFDay == TimeSpan.FromHours(18))
或任何时候最有意义。
后一个例子可以解释为(d => d.TimeOfDay == TimeSpan.FromHours(8) && (d.DayOfWeek == Monday || d.DayOfWeek == Wednesday || d.DayOfWeek == Friday))
。
然后,我可以在开始日期和结束日期之间循环每小时,如果函数返回true,则将时间添加到日程表中。
我遇到的麻烦是解析。我目前的解决方案是创建一个字典,其中包含我可能期望的所有短语,以及适当的过滤器作为值。然而,这开始变得非常混乱和不可持续,尤其是可能的重叠量:
var phrases = new Dictionary<string, Func<DateTime, bool>>()
{
{ "DAILY", (d => true) },
{ "A DAY", (d => true) },
{ "PER DAY", (d => true) },
{ "EVERY DAY", (d => true) },
{ "SUNDAY", (d => d.DayOfWeek == DayOfWeek.Sunday) },
{ "SUN", (d => d.DayOfWeek == DayOfWeek.Sunday) },
{ "MONDAY", (d => d.DayOfWeek == DayOfWeek.Monday) },
{ "MON", (d => d.DayOfWeek == DayOfWeek.Monday) },
. . .
}
有什么更好的方法可以做到这一点?
答案 0 :(得分:0)
完全处理这个问题非常困难。我在.NET的自然语言引擎(https://nuget.org/packages/AboditNLP/)中处理了许多(但不是全部)可能性。
其中一个挑战是英语含糊不清:“星期一”可能意味着本星期一,下周一或上周一取决于具体情况。
您的基本方法很好:将日期时间映射到所需值的函数组合在一起。但是,函数的输出可能需要是单个日期时间或日期时间范围,或日期时间范围的集合(例如,2013年5月的每个星期一)。人们使用的短语实际上是无限范围的,你可能需要枚举这些短语以获得下一个(或几个)(例如每个星期一)。
英语DateTime表达式可以表达查询或生成序列。对数据库进行查询(SQL或LINQ表达式)所需的内容可能与将表达式放入日历条目时所需的内容大不相同。
.NET中的内置Datetime和TimeSpan类不足以代表您将遇到的大多数英语日期时间表达式。它们无法表示像“两周”这样的常见间隔,也无法处理范围,集合,交集,并集以及所需的所有其他组合。
从解析的角度来看,你不能简单地从左到右。与算术一样,时间运算符可能具有优先级规则。例如,“五月的最后一个星期五”确实需要作为InfiniteRepeatEveryYear(LastOf(IntersectionOf(all Fridays, all Mays)))
处理,即“五月星期五”需要解析才能将“最后一个”应用到它。
这是一个非常难的问题,祝你好运!