private DTParseResult Match2Time(Match match, DateObject referenceTime) { var ret = new DTParseResult(); int hour = 0, min = 0, second = 0, day = referenceTime.Day, month = referenceTime.Month, year = referenceTime.Year; bool hasMin = false, hasSec = false, hasAm = false, hasPm = false; var engTimeStr = match.Groups["engtime"].Value; if (!string.IsNullOrEmpty(engTimeStr)) { // get hour var hourStr = match.Groups["hournum"].Value.ToLower(); hour = this.config.Numbers[hourStr]; // get minute var minStr = match.Groups["minnum"].Value; var tensStr = match.Groups["tens"].Value; if (!string.IsNullOrEmpty(minStr)) { min = this.config.Numbers[minStr]; if (!string.IsNullOrEmpty(tensStr)) { min += this.config.Numbers[tensStr]; } hasMin = true; } } else { // get hour var hourStr = match.Groups["hour"].Value; if (string.IsNullOrEmpty(hourStr)) { hourStr = match.Groups["hournum"].Value.ToLower(); if (!this.config.Numbers.TryGetValue(hourStr, out hour)) { return(ret); } } else { hour = int.Parse(hourStr); } // get minute var minStr = match.Groups["min"].Value.ToLower(); if (string.IsNullOrEmpty(minStr)) { minStr = match.Groups["minnum"].Value; if (!string.IsNullOrEmpty(minStr)) { min = this.config.Numbers[minStr]; hasMin = true; } var tensStr = match.Groups["tens"].Value; if (!string.IsNullOrEmpty(tensStr)) { min += this.config.Numbers[tensStr]; hasMin = true; } } else { min = int.Parse(minStr); hasMin = true; } // get second var secStr = match.Groups["sec"].Value.ToLower(); if (!string.IsNullOrEmpty(secStr)) { second = int.Parse(secStr); hasSec = true; } } //adjust by desc string var descStr = match.Groups["desc"].Value.ToLower(); if (!string.IsNullOrEmpty(descStr)) { if (descStr.ToLower().StartsWith("a")) { if (hour >= 12) { hour -= 12; } hasAm = true; } else if (descStr.ToLower().StartsWith("p")) { if (hour < 12) { hour += 12; } hasPm = true; } } // adjust min by prefix var timePrefix = match.Groups["prefix"].Value.ToLower(); if (!string.IsNullOrEmpty(timePrefix)) { this.config.AdjustByPrefix(timePrefix, ref hour, ref min, ref hasMin); } // adjust hour by suffix var timeSuffix = match.Groups["suffix"].Value.ToLower(); if (!string.IsNullOrEmpty(timeSuffix)) { this.config.AdjustBySuffix(timeSuffix, ref hour, ref min, ref hasMin, ref hasAm, ref hasPm); } if (hour == 24) { hour = 0; } ret.Timex = "T" + hour.ToString("D2"); if (hasMin) { ret.Timex += ":" + min.ToString("D2"); } if (hasSec) { ret.Timex += ":" + second.ToString("D2"); } if (hour <= 12 && !hasPm && !hasAm) { ret.comment = "ampm"; } ret.FutureValue = ret.PastValue = new DateObject(year, month, day, hour, min, second); ret.Success = true; return(ret); }
private DTParseResult ParseOneWordPeriod(string text, DateObject referenceDate) { var ret = new DTParseResult(); int year = referenceDate.Year, month = referenceDate.Month; int futureYear = year, pastYear = year; var trimedText = text.Trim().ToLower(); var match = this.config.OneWordPeriodRegex.Match(trimedText); if (match.Success && match.Index == 0 && match.Length == trimedText.Length) { var monthStr = match.Groups["month"].Value; if (this.config.IsYearToDate(trimedText)) { ret.Timex = referenceDate.Year.ToString("D4"); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(new DateObject(referenceDate.Year, 1, 1), referenceDate); ret.Success = true; return(ret); } if (this.config.IsMonthToDate(trimedText)) { ret.Timex = referenceDate.Year.ToString("D4") + "-" + referenceDate.Month.ToString("D2"); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>( new DateObject(referenceDate.Year, referenceDate.Month, 1), referenceDate); ret.Success = true; return(ret); } if (!string.IsNullOrEmpty(monthStr)) { var swift = this.config.GetSwiftYear(trimedText); month = this.config.MonthOfYear[monthStr.ToLower()]; if (swift >= -1) { ret.Timex = (referenceDate.Year + swift).ToString("D4") + "-" + month.ToString("D2"); year = year + swift; futureYear = pastYear = year; } else { ret.Timex = "XXXX-" + month.ToString("D2"); if (month < referenceDate.Month) { futureYear++; } if (month >= referenceDate.Month) { pastYear--; } } } else { var swift = this.config.GetSwiftDay(trimedText); if (this.config.IsWeekOnly(trimedText)) { var monday = referenceDate.This(DayOfWeek.Monday).AddDays(7 * swift); ret.Timex = monday.Year.ToString("D4") + "-W" + _cal.GetWeekOfYear(monday, CalendarWeekRule.FirstDay, DayOfWeek.Monday) .ToString("D2"); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>( referenceDate.This(DayOfWeek.Monday).AddDays(7 * swift), referenceDate.This(DayOfWeek.Sunday).AddDays(7 * swift).AddDays(1)); ret.Success = true; return(ret); } if (this.config.IsWeekend(trimedText)) { DateObject beginDate, endDate; beginDate = referenceDate.This(DayOfWeek.Saturday).AddDays(7 * swift); endDate = referenceDate.This(DayOfWeek.Sunday).AddDays(7 * swift); ret.Timex = beginDate.Year.ToString("D4") + "-W" + _cal.GetWeekOfYear(beginDate, CalendarWeekRule.FirstDay, DayOfWeek.Monday) .ToString("D2") + "-WE"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate.AddDays(1)); ret.Success = true; return(ret); } if (this.config.IsMonthOnly(trimedText)) { month = referenceDate.AddMonths(swift).Month; year = referenceDate.AddMonths(swift).Year; ret.Timex = year.ToString("D4") + "-" + month.ToString("D2"); futureYear = pastYear = year; } else if (this.config.IsYearOnly(trimedText)) { year = referenceDate.AddYears(swift).Year; ret.Timex = year.ToString("D4"); ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(new DateObject(year, 1, 1), new DateObject(year, 12, 31).AddDays(1)); ret.Success = true; return(ret); } } } else { return(ret); } // only "month" will come to here ret.FutureValue = new Tuple <DateObject, DateObject>( new DateObject(futureYear, month, 1), new DateObject(futureYear, month, 1).AddMonths(1)); ret.PastValue = new Tuple <DateObject, DateObject>( new DateObject(pastYear, month, 1), new DateObject(pastYear, month, 1).AddMonths(1)); ret.Success = true; return(ret); }
private DTParseResult ParseNumberWithUnit(string text, DateObject referenceDate) { var ret = new DTParseResult(); var numStr = string.Empty; var unitStr = string.Empty; // if there are spaces between nubmer and unit var ers = this.config.CardinalExtractor.Extract(text); if (ers.Count == 1) { var pr = this.config.NumberParser.Parse(ers[0]); var srcUnit = text.Substring(ers[0].Start + ers[0].Length ?? 0).Trim().ToLowerInvariant(); var beforeStr = text.Substring(0, ers[0].Start ?? 0).Trim().ToLowerInvariant(); if (this.config.UnitMap.ContainsKey(srcUnit)) { numStr = pr.ResolutionStr; unitStr = this.config.UnitMap[srcUnit]; var prefixMatch = this.config.PastRegex.Match(beforeStr); if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length) { DateObject beginDate, endDate; switch (unitStr) { case "D": beginDate = referenceDate.AddDays(-(double)pr.Value); endDate = referenceDate; break; case "W": beginDate = referenceDate.AddDays(-7 * (double)pr.Value); endDate = referenceDate; break; case "MON": beginDate = referenceDate.AddMonths(-Convert.ToInt32((double)pr.Value)); endDate = referenceDate; break; case "Y": beginDate = referenceDate.AddYears(-Convert.ToInt32((double)pr.Value)); endDate = referenceDate; break; default: return(ret); } ret.Timex = $"({Util.LuisDate(beginDate)},{Util.LuisDate(endDate)},P{numStr}{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate); ret.Success = true; return(ret); } prefixMatch = this.config.FutureRegex.Match(beforeStr); if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length) { DateObject beginDate, endDate; switch (unitStr) { case "D": beginDate = referenceDate; endDate = referenceDate.AddDays((double)pr.Value); break; case "W": beginDate = referenceDate; endDate = referenceDate.AddDays(7 * (double)pr.Value); break; case "MON": beginDate = referenceDate; endDate = referenceDate.AddMonths(Convert.ToInt32((double)pr.Value)); break; case "Y": beginDate = referenceDate; endDate = referenceDate.AddYears(Convert.ToInt32((double)pr.Value)); break; default: return(ret); } ret.Timex = $"({Util.LuisDate(beginDate.AddDays(1))},{Util.LuisDate(endDate.AddDays(1))},P{numStr}{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate.AddDays(1), endDate.AddDays(1)); ret.Success = true; return(ret); } } } // if there are NO spaces between number and unit var match = this.config.NumberCombinedWithUnit.Match(text); if (match.Success) { var srcUnit = match.Groups["unit"].Value.ToLowerInvariant(); var beforeStr = text.Substring(0, match.Index).Trim().ToLowerInvariant(); if (this.config.UnitMap.ContainsKey(srcUnit)) { unitStr = this.config.UnitMap[srcUnit]; numStr = match.Groups["num"].Value; var prefixMatch = this.config.PastRegex.Match(beforeStr); if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length) { DateObject beginDate, endDate; switch (unitStr) { case "D": beginDate = referenceDate.AddDays(-double.Parse(numStr)); endDate = referenceDate; break; case "W": beginDate = referenceDate.AddDays(-7 * double.Parse(numStr)); endDate = referenceDate; break; case "MON": beginDate = referenceDate.AddMonths(-Convert.ToInt32(double.Parse(numStr))); endDate = referenceDate; break; case "Y": beginDate = referenceDate.AddYears(-Convert.ToInt32(double.Parse(numStr))); endDate = referenceDate; break; default: return(ret); } ret.Timex = $"({Util.LuisDate(beginDate)},{Util.LuisDate(endDate)},P{numStr}{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate); ret.Success = true; return(ret); } prefixMatch = this.config.FutureRegex.Match(beforeStr); if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length) { DateObject beginDate, endDate; switch (unitStr) { case "D": beginDate = referenceDate; endDate = referenceDate.AddDays(double.Parse(numStr)); break; case "W": beginDate = referenceDate; endDate = referenceDate.AddDays(7 * double.Parse(numStr)); break; case "MON": beginDate = referenceDate; endDate = referenceDate.AddMonths(Convert.ToInt32(double.Parse(numStr))); break; case "Y": beginDate = referenceDate; endDate = referenceDate.AddYears(Convert.ToInt32(double.Parse(numStr))); break; default: return(ret); } ret.Timex = $"({Util.LuisDate(beginDate.AddDays(1))},{Util.LuisDate(endDate.AddDays(1))},P{numStr}{unitStr[0]})"; ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate.AddDays(1), endDate.AddDays(1)); ret.Success = true; return(ret); } } } return(ret); }
private DTParseResult ParseSimpleCases(string text, DateObject referenceDate) { var ret = new DTParseResult(); int year = referenceDate.Year, month = referenceDate.Month; int beginDay = referenceDate.Day, endDay = referenceDate.Day; var noYear = false; var trimedText = text.Trim(); var match = this.config.MonthFrontBetweenRegex.Match(trimedText); string beginLuisStr = string.Empty, endLuisStr = string.Empty; if (!match.Success) { match = this.config.BetweenRegex.Match(trimedText); } if (!match.Success) { match = this.config.MonthFrontSimpleCasesRegex.Match(trimedText); } if (!match.Success) { match = this.config.SimpleCasesRegex.Match(trimedText); } if (match.Success && match.Index == 0 && match.Length == trimedText.Length) { var days = match.Groups["day"]; beginDay = this.config.DayOfMonth[days.Captures[0].Value.ToLower()]; endDay = this.config.DayOfMonth[days.Captures[1].Value.ToLower()]; var monthStr = match.Groups["month"].Value; if (!string.IsNullOrEmpty(monthStr)) { month = this.config.MonthOfYear[monthStr.ToLower()]; noYear = true; } else { monthStr = match.Groups["relmonth"].Value.Trim().ToLower(); var swiftMonth = this.config.GetSwiftMonth(monthStr); switch (swiftMonth) { case 1: if (month != 12) { month += 1; } else { month = 1; year += 1; } break; case -1: if (month != 1) { month -= 1; } else { month = 12; year -= 1; } break; default: break; } } if (this.config.IsFuture(monthStr)) { beginLuisStr = Util.LuisDate(year, month, beginDay); endLuisStr = Util.LuisDate(year, month, endDay); } else { beginLuisStr = Util.LuisDate(-1, month, beginDay); endLuisStr = Util.LuisDate(-1, month, endDay); } } else { return(ret); } // parse year var yearStr = match.Groups["year"].Value; if (!string.IsNullOrEmpty(yearStr)) { year = int.Parse(yearStr); noYear = false; } int futureYear = year, pastYear = year; var startDate = new DateObject(year, month, beginDay); if (noYear && startDate < referenceDate) { futureYear++; } if (noYear && startDate >= referenceDate) { pastYear--; } ret.Timex = $"({beginLuisStr},{endLuisStr},P{endDay - beginDay}D)"; ret.FutureValue = new Tuple <DateObject, DateObject>( new DateObject(futureYear, month, beginDay), new DateObject(futureYear, month, endDay)); ret.PastValue = new Tuple <DateObject, DateObject>( new DateObject(pastYear, month, beginDay), new DateObject(pastYear, month, endDay)); ret.Success = true; return(ret); }
// merge a Date entity and a Time entity private DTParseResult MergeDateAndTime(string text, DateObject referenceTime) { var ret = new DTParseResult(); var er1 = this.config.DateExtractor.Extract(text); if (er1.Count == 0) { er1 = this.config.DateExtractor.Extract(this.config.TokenBeforeDate + text); if (er1.Count == 1) { er1[0].Start -= this.config.TokenBeforeDate.Length; } else { return(ret); } } else { // this is to understand if there is an ambiguous token in the text. For some languages (e.g. spanish) // the same word could mean different things (e.g a time in the day or an specific day). if (this.config.HaveAmbiguousToken(text, er1[0].Text)) { return(ret); } } var er2 = this.config.TimeExtractor.Extract(text); if (er2.Count == 0) { // here we filter out "morning, afternoon, night..." time entities er2 = this.config.TimeExtractor.Extract(this.config.TokenBeforeTime + text); if (er2.Count == 1) { er2[0].Start -= this.config.TokenBeforeTime.Length; } else { return(ret); } } // handle case "Oct. 5 in the afternoon at 7:00" // in this case "5 in the afternoon" will be extract as a Time entity var correctTimeIdx = 0; while (correctTimeIdx < er2.Count && er2[correctTimeIdx].IsOverlap(er1[0])) { correctTimeIdx++; } if (correctTimeIdx >= er2.Count) { return(ret); } var pr1 = this.config.DateParser.Parse(er1[0], referenceTime.Date); var pr2 = this.config.TimeParser.Parse(er2[correctTimeIdx], referenceTime); if (pr1.Value == null || pr2.Value == null) { return(ret); } var futureDate = (DateObject)((DTParseResult)pr1.Value).FutureValue; var pastDate = (DateObject)((DTParseResult)pr1.Value).PastValue; var time = (DateObject)((DTParseResult)pr2.Value).FutureValue; var hour = time.Hour; var min = time.Minute; var sec = time.Second; // handle morning, afternoon if (this.config.PMTimeRegex.IsMatch(text) && hour < 12) { hour += 12; } else if (this.config.AMTimeRegex.IsMatch(text) && hour >= 12) { hour -= 12; } var timeStr = pr2.TimexStr; if (timeStr.EndsWith("ampm")) { timeStr = timeStr.Substring(0, timeStr.Length - 4); } timeStr = "T" + hour.ToString("D2") + timeStr.Substring(3); ret.Timex = pr1.TimexStr + timeStr; var val = (DTParseResult)pr2.Value; if (hour <= 12 && !this.config.PMTimeRegex.IsMatch(text) && !this.config.AMTimeRegex.IsMatch(text) && !string.IsNullOrEmpty(val.comment)) { //ret.Timex += "ampm"; ret.comment = "ampm"; } ret.FutureValue = new DateObject(futureDate.Year, futureDate.Month, futureDate.Day, hour, min, sec); ret.PastValue = new DateObject(pastDate.Year, pastDate.Month, pastDate.Day, hour, min, sec); ret.Success = true; return(ret); }
private DTParseResult ParseTimeOfToday(string text, DateObject referenceTime) { var ret = new DTParseResult(); var trimedText = text.ToLowerInvariant().Trim(); int hour = 0, min = 0, sec = 0; string timeStr = string.Empty; var wholeMatch = this.config.SimpleTimeOfTodayAfterRegex.Match(trimedText); if (!(wholeMatch.Success && wholeMatch.Length == trimedText.Length)) { wholeMatch = this.config.SimpleTimeOfTodayBeforeRegex.Match(trimedText); } if (wholeMatch.Success && wholeMatch.Length == trimedText.Length) { var hourStr = wholeMatch.Groups["hour"].Value; if (string.IsNullOrEmpty(hourStr)) { hourStr = wholeMatch.Groups["hournum"].Value.ToLower(); hour = this.config.Numbers[hourStr]; } else { hour = int.Parse(hourStr); } timeStr = "T" + hour.ToString("D2"); } else { var ers = this.config.TimeExtractor.Extract(trimedText); if (ers.Count != 1) { ers = this.config.TimeExtractor.Extract(this.config.TokenBeforeTime + trimedText); if (ers.Count == 1) { ers[0].Start -= this.config.TokenBeforeTime.Length; } else { return(ret); } } var pr = this.config.TimeParser.Parse(ers[0], referenceTime); if (pr.Value == null) { return(ret); } var time = (DateObject)((DTParseResult)pr.Value).FutureValue; hour = time.Hour; min = time.Minute; sec = time.Second; timeStr = pr.TimexStr; } var match = this.config.SpecificNightRegex.Match(trimedText); if (match.Success) { var matchStr = match.Value.ToLowerInvariant(); // handle "last", "next" var swift = this.config.GetSwiftDay(matchStr); var date = referenceTime.AddDays(swift).Date; // handle "morning", "afternoon" hour = this.config.GetHour(matchStr, hour); // in this situation, luisStr cannot end up with "ampm", because we always have a "morning" or "night" if (timeStr.EndsWith("ampm")) { timeStr = timeStr.Substring(0, timeStr.Length - 4); } timeStr = "T" + hour.ToString("D2") + timeStr.Substring(3); ret.Timex = Util.FormatDate(date) + timeStr; ret.FutureValue = ret.PastValue = new DateObject(date.Year, date.Month, date.Day, hour, min, sec); ret.Success = true; return(ret); } return(ret); }
// simple cases made by a number followed an unit private DTParseResult ParseNumerWithUnit(string text, DateObject referenceTime) { var ret = new DTParseResult(); var numStr = string.Empty; var unitStr = string.Empty; // if there are spaces between nubmer and unit var ers = this.config.CardinalExtractor.Extract(text); if (ers.Count == 1) { var pr = this.config.NumberParser.Parse(ers[0]); var srcUnit = text.Substring(ers[0].Start + ers[0].Length ?? 0).Trim().ToLower(); if (this.config.UnitMap.ContainsKey(srcUnit)) { numStr = pr.Value.ToString(); unitStr = this.config.UnitMap[srcUnit]; ret.Timex = "P" + (IsLessThanDay(unitStr) ? "T" : "") + numStr + unitStr[0]; ret.FutureValue = ret.PastValue = (double)pr.Value * this.config.UnitValueMap[srcUnit]; ret.Success = true; return(ret); } } // if there are NO spaces between number and unit var match = this.config.NumberCombinedWithUnit.Match(text); if (match.Success) { numStr = match.Groups["num"].Value; var srcUnit = match.Groups["unit"].Value.ToLower(); if (this.config.UnitMap.ContainsKey(srcUnit)) { unitStr = this.config.UnitMap[srcUnit]; ret.Timex = "P" + (IsLessThanDay(unitStr) ? "T" : "") + numStr + unitStr[0]; ret.FutureValue = ret.PastValue = double.Parse(numStr) * this.config.UnitValueMap[srcUnit]; ret.Success = true; return(ret); } } match = this.config.AnUnitRegex.Match(text); if (match.Success) { numStr = "1"; var srcUnit = match.Groups["unit"].Value.ToLower(); if (this.config.UnitMap.ContainsKey(srcUnit)) { unitStr = this.config.UnitMap[srcUnit]; ret.Timex = "P" + (IsLessThanDay(unitStr) ? "T" : "") + numStr + unitStr[0]; ret.FutureValue = ret.PastValue = double.Parse(numStr) * this.config.UnitValueMap[srcUnit]; ret.Success = true; return(ret); } } return(ret); }
private DTParseResult Match2Date(Match match, DateObject referenceDate) { var ret = new DTParseResult(); var holidayStr = this.config.SanitizeHolidayToken(match.Groups["holiday"].Value.ToLowerInvariant()); // get year (if exist) var yearStr = match.Groups["year"].Value.ToLower(); var orderStr = match.Groups["order"].Value.ToLower(); int year; var hasYear = false; if (!string.IsNullOrEmpty(yearStr)) { year = int.Parse(yearStr); hasYear = true; } else if (!string.IsNullOrEmpty(orderStr)) { var swift = this.config.GetSwiftYear(orderStr); if (swift < -1) { return(ret); } year = referenceDate.Year + swift; hasYear = true; } else { year = referenceDate.Year; } string holidayKey = string.Empty; foreach (var holidayPair in this.config.HolidayNames) { if (holidayPair.Value.Contains(holidayStr)) { holidayKey = holidayPair.Key; break; } } var timexStr = string.Empty; if (!string.IsNullOrEmpty(holidayKey)) { var value = referenceDate; Func <int, DateObject> function; if (this.config.HolidayFuncDictionary.TryGetValue(holidayKey, out function)) { value = function(year); this.config.VariableHolidaysTimexDictionary.TryGetValue(holidayKey, out timexStr); if (string.IsNullOrEmpty(timexStr)) { timexStr = $"-{value.Month:D2}-{value.Day:D2}"; } } if (function == null) { return(ret); } if (hasYear) { ret.Timex = year.ToString("D4") + timexStr; ret.FutureValue = ret.PastValue = new DateObject(year, value.Month, value.Day); ret.Success = true; return(ret); } ret.Timex = "XXXX" + timexStr; ret.FutureValue = GetFutureValue(value, referenceDate, holidayKey); ret.PastValue = GetPastValue(value, referenceDate, holidayKey); ret.Success = true; return(ret); } return(ret); }