2

我正在研究一个字符串解析器,它将读取一个短语或句子并解析它以获取时间表/时间信息。例如,输入可能包括短语

“每天两次”

或者

“周一、周三和周五”

目标是创建一个模板,该模板可以转换为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) },
    . . .
}

有什么更好的方法来做到这一点?

4

1 回答 1

0

要彻底解决这个问题是一个非常困难的问题。我在我的 .NET 自然语言引擎 ( https://nuget.org/packages/AboditNLP/ ) 中处理了许多(但不是全部)可能性。

挑战之一是英语模棱两可:“MONDAY”可能表示本周一、下周一或上周一,具体取决于上下文。

您的基本方法是一个很好的方法:组合将日期时间映射到所需值的函数。但函数的输出可能需要是单个日期时间或日期时间范围,或日期时间范围的集合(例如 2013 年 5 月的每个星期一)。人们使用的许多短语实际上是无限范围的,您可能需要列举这些短语以获得下一个(或多个)(例如每周一)。

英文 DateTime 表达式可以表示查询或生成序列。您想要查询数据库(SQL 或 LINQ 表达式)的内容可能与将表达式放入日历条目时想要的内容大不相同。

.NET 中的内置 Datetime 和 TimeSpan 类不足以表示您将遇到的大多数英语日期时间表达式。它们无法表示像“两周”这样的常见间隔,也无法处理范围、集合、交集、并集以及您需要的所有其他组合。

从解析的角度来看,您不能简单地从左到右。像算术一样,时间运算符可能有优先规则。例如,“五月的最后一个星期五”确实需要处理为InfiniteRepeatEveryYear(LastOf(IntersectionOf(all Fridays, all Mays))),即“五月的星期五”需要解析才能应用“最后一个”。

这是一个非常困难的问题,祝你好运!

于 2013-06-04T16:07:32.247 回答