public static List <Token> ExtractorDurationWithBeforeAndAfter(string text, ExtractResult er, List <Token> ret, IDateTimeUtilityConfiguration utilityConfiguration) { var pos = (int)er.Start + (int)er.Length; if (pos <= text.Length) { var afterString = text.Substring(pos); var beforeString = text.Substring(0, (int)er.Start); var index = -1; if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.AgoStringList, out index)) { ret.Add(new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index)); } else if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.LaterStringList, out index)) { ret.Add(new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index)); } else if (MatchingUtil.GetInIndex(beforeString, utilityConfiguration.InStringList, out index)) { if (er.Start != null && er.Length != null && (int)er.Start > index) { ret.Add(new Token((int)er.Start - index, (int)er.Start + (int)er.Length)); } } } return(ret); }
public static List <Token> ExtractorDurationWithBeforeAndAfter(string text, ExtractResult er, List <Token> ret, IDateTimeUtilityConfiguration utilityConfiguration) { var pos = (int)er.Start + (int)er.Length; if (pos <= text.Length) { var afterString = text.Substring(pos); var beforeString = text.Substring(0, (int)er.Start); var index = -1; if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.AgoRegex, out index)) { ret.Add(new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index)); } else if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.LaterRegex, out index)) { ret.Add(new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index)); } else if (MatchingUtil.GetInIndex(beforeString, utilityConfiguration.InConnectorRegex, out index)) { // for range unit like "week, month, year", it should output dateRange or datetimeRange if (!utilityConfiguration.RangeUnitRegex.IsMatch(er.Text)) { if (er.Start != null && er.Length != null && (int)er.Start >= index) { ret.Add(new Token((int)er.Start - index, (int)er.Start + (int)er.Length)); } } } } return(ret); }
public static List <Token> ExtractorDurationWithBeforeAndAfter(string text, ExtractResult er, List <Token> ret, IDateTimeUtilityConfiguration utilityConfiguration) { var pos = (int)er.Start + (int)er.Length; if (pos <= text.Length) { var afterString = text.Substring(pos); var beforeString = text.Substring(0, (int)er.Start); var index = -1; var isTimeDuration = utilityConfiguration.TimeUnitRegex.Match(er.Text).Success; if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.AgoRegex, out index)) { // We don't support cases like "5 minutes from today" for now // Cases like "5 minutes ago" or "5 minutes from now" are supported // Cases like "2 days before today" or "2 weeks from today" are also supported var isDayMatchInAfterString = utilityConfiguration.AgoRegex.Match(afterString).Groups["day"].Success; if (!(isTimeDuration && isDayMatchInAfterString)) { ret.Add(new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index)); } } else if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.LaterRegex, out index)) { var isDayMatchInAfterString = utilityConfiguration.LaterRegex.Match(afterString).Groups["day"].Success; if (!(isTimeDuration && isDayMatchInAfterString)) { ret.Add(new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index)); } } else if (MatchingUtil.GetTermIndex(beforeString, utilityConfiguration.InConnectorRegex, out index)) { // For range unit like "week, month, year", it should output dateRange or datetimeRange if (!utilityConfiguration.RangeUnitRegex.IsMatch(er.Text)) { if (er.Start != null && er.Length != null && (int)er.Start >= index) { ret.Add(new Token((int)er.Start - index, (int)er.Start + (int)er.Length)); } } } else if (MatchingUtil.GetTermIndex(beforeString, utilityConfiguration.WithinNextPrefixRegex, out index)) { // For range unit like "week, month, year, day, second, minute, hour", it should output dateRange or datetimeRange if (!utilityConfiguration.DateUnitRegex.IsMatch(er.Text) && !utilityConfiguration.TimeUnitRegex.IsMatch(er.Text)) { if (er.Start != null && er.Length != null && (int)er.Start >= index) { ret.Add(new Token((int)er.Start - index, (int)er.Start + (int)er.Length)); } } } } return(ret); }
public List <ExtractResult> Extract(string text, DateObject reference) { var ret = new List <ExtractResult>(); var originText = text; List <MatchResult <string> > superfluousWordMatches = null; if ((this.config.Options & DateTimeOptions.EnablePreview) != 0) { text = MatchingUtil.PreProcessTextRemoveSuperfluousWords(text, this.config.SuperfluousWordMatcher, out superfluousWordMatches); } // The order is important, since there can be conflicts in merging AddTo(ret, this.config.DateExtractor.Extract(text, reference), text); AddTo(ret, this.config.TimeExtractor.Extract(text, reference), text); AddTo(ret, this.config.DatePeriodExtractor.Extract(text, reference), text); AddTo(ret, this.config.DurationExtractor.Extract(text, reference), text); AddTo(ret, this.config.TimePeriodExtractor.Extract(text, reference), text); AddTo(ret, this.config.DateTimePeriodExtractor.Extract(text, reference), text); AddTo(ret, this.config.DateTimeExtractor.Extract(text, reference), text); AddTo(ret, this.config.SetExtractor.Extract(text, reference), text); AddTo(ret, this.config.HolidayExtractor.Extract(text, reference), text); if ((this.config.Options & DateTimeOptions.EnablePreview) != 0) { AddTo(ret, this.config.TimeZoneExtractor.Extract(text, reference), text); ret = this.config.TimeZoneExtractor.RemoveAmbiguousTimezone(ret); } // This should be at the end since if need the extractor to determine the previous text contains time or not AddTo(ret, NumberEndingRegexMatch(text, ret), text); // Modify time entity to an alternative DateTime expression if it follows a DateTime entity if ((this.config.Options & DateTimeOptions.ExtendedTypes) != 0) { ret = this.config.DateTimeAltExtractor.Extract(ret, text, reference); } ret = FilterUnspecificDatePeriod(ret); ret = FilterAmbiguity(ret, text); ret = AddMod(ret, text); // Filtering if ((this.config.Options & DateTimeOptions.CalendarMode) != 0) { ret = CheckCalendarFilterList(ret, text); } ret = ret.OrderBy(p => p.Start).ToList(); if ((this.config.Options & DateTimeOptions.EnablePreview) != 0) { ret = MatchingUtil.PosProcessExtractionRecoverSuperfluousWords(ret, superfluousWordMatches, originText); } return(ret); }
private static DateTimeResolutionResult GetAgoLaterResult( DateTimeParseResult durationParseResult, double number, IImmutableDictionary <string, string> unitMap, string srcUnit, string afterStr, string beforeStr, System.DateTime referenceTime, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode) { var ret = new DateTimeResolutionResult(); if (unitMap.ContainsKey(srcUnit)) { var unitStr = unitMap[srcUnit]; var numStr = number.ToString(CultureInfo.InvariantCulture); var result = new DateTimeResolutionResult(); if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.AgoRegex)) { if (mode.Equals(AgoLaterMode.Date)) { result = GetDateResult(unitStr, numStr, referenceTime, false); } else if (mode.Equals(AgoLaterMode.DateTime)) { result = GetDateTimeResult(unitStr, numStr, referenceTime, false); } ((DateTimeResolutionResult)durationParseResult.Value).Mod = TimeTypeConstants.beforeMod; result.SubDateTimeEntities = new List <object> { durationParseResult }; return(result); } if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsInIndex(beforeStr, utilityConfiguration.InConnectorRegex)) { if (mode.Equals(AgoLaterMode.Date)) { result = GetDateResult(unitStr, numStr, referenceTime, true); } else if (mode.Equals(AgoLaterMode.DateTime)) { result = GetDateTimeResult(unitStr, numStr, referenceTime, true); } ((DateTimeResolutionResult)durationParseResult.Value).Mod = TimeTypeConstants.afterMod; result.SubDateTimeEntities = new List <object> { durationParseResult }; return(result); } } return(ret); }
private static DateTimeResolutionResult GetAgoLaterResult( DateTimeParseResult durationParseResult, string afterStr, string beforeStr, System.DateTime referenceTime, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode) { var ret = new DateTimeResolutionResult(); var resultDateTime = referenceTime; var timex = durationParseResult.TimexStr; if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.MORE_THAN_MOD) { ret.Mod = Constants.MORE_THAN_MOD; } else if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.LESS_THAN_MOD) { ret.Mod = Constants.LESS_THAN_MOD; } if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.AgoRegex)) { resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime, false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.BEFORE_MOD; } else if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsTermIndex(beforeStr, utilityConfiguration.InConnectorRegex)) { resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime, true); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.AFTER_MOD; } if (resultDateTime != referenceTime) { if (mode.Equals(AgoLaterMode.Date)) { ret.Timex = $"{FormatUtil.LuisDate(resultDateTime)}"; } else if (mode.Equals(AgoLaterMode.DateTime)) { ret.Timex = $"{FormatUtil.LuisDateTime(resultDateTime)}"; } ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { durationParseResult }; ret.Success = true; } return(ret); }
private static DateTimeResolutionResult GetAgoLaterResult(IParser numberParser, ExtractResult er, IImmutableDictionary <string, string> unitMap, string srcUnit, string afterStr, string beforeStr, System.DateTime referenceTime, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode) { var ret = new DateTimeResolutionResult(); var pr = numberParser.Parse(er); var number = int.Parse(pr.ResolutionStr); if (unitMap.ContainsKey(srcUnit)) { var unitStr = unitMap[srcUnit]; var numStr = number.ToString(); if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.AgoStringList)) { if (mode.Equals(AgoLaterMode.Date)) { return(GetDateResult(unitStr, numStr, referenceTime, false)); } if (mode.Equals(AgoLaterMode.DateTime)) { return(GetDateTimeResult(unitStr, numStr, referenceTime, false)); } } if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterStringList) || MatchingUtil.ContainsInIndex(beforeStr, utilityConfiguration.InStringList)) { if (mode.Equals(AgoLaterMode.Date)) { return(GetDateResult(unitStr, numStr, referenceTime, true)); } if (mode.Equals(AgoLaterMode.DateTime)) { return(GetDateTimeResult(unitStr, numStr, referenceTime, true)); } } } return(ret); }
private IEnumerable <Token> MatchLocationTimes(string text) { var ret = new List <Token>(); if (config.LocationTimeSuffixRegex == null) { return(ret); } var timeMatch = config.LocationTimeSuffixRegex.Matches(text); if (timeMatch.Count != 0) { var lastMatchIndex = timeMatch[timeMatch.Count - 1].Index; var matches = config.LocationMatcher.Find(text.Substring(0, lastMatchIndex).ToLowerInvariant()); var locationMatches = MatchingUtil.RemoveSubMatches(matches); var i = 0; foreach (Match match in timeMatch) { var hasCityBefore = false; while (i < locationMatches.Count && locationMatches[i].End <= match.Index) { hasCityBefore = true; i++; if (i == locationMatches.Count) { break; } } if (hasCityBefore && locationMatches[i - 1].End == match.Index) { ret.Add(new Token(locationMatches[i - 1].Start, match.Index + match.Length)); } if (i == locationMatches.Count) { break; } } } return(ret); }
private static DateTimeResolutionResult GetAgoLaterResult(double number, IImmutableDictionary <string, string> unitMap, string srcUnit, string afterStr, string beforeStr, System.DateTime referenceTime, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode) { var ret = new DateTimeResolutionResult(); if (unitMap.ContainsKey(srcUnit)) { var unitStr = unitMap[srcUnit]; var numStr = number.ToString(CultureInfo.InvariantCulture); if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.AgoRegex)) { if (mode.Equals(AgoLaterMode.Date)) { return(GetDateResult(unitStr, numStr, referenceTime, false)); } if (mode.Equals(AgoLaterMode.DateTime)) { return(GetDateTimeResult(unitStr, numStr, referenceTime, false)); } } if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsInIndex(beforeStr, utilityConfiguration.InConnectorRegex)) { if (mode.Equals(AgoLaterMode.Date)) { return(GetDateResult(unitStr, numStr, referenceTime, true)); } if (mode.Equals(AgoLaterMode.DateTime)) { return(GetDateTimeResult(unitStr, numStr, referenceTime, true)); } } } return(ret); }
private static DateTimeResolutionResult GetAgoLaterResult( DateTimeParseResult durationParseResult, string afterStr, string beforeStr, DateObject referenceTime, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode, SwiftDayDelegate swiftDay) { var ret = new DateTimeResolutionResult(); var resultDateTime = referenceTime; var timex = durationParseResult.TimexStr; if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.MORE_THAN_MOD) { ret.Mod = Constants.MORE_THAN_MOD; } else if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.LESS_THAN_MOD) { ret.Mod = Constants.LESS_THAN_MOD; } if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.AgoRegex)) { var match = utilityConfiguration.AgoRegex.Match(afterStr); var swift = 0; // Handle cases like "3 days before yesterday" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.BEFORE_MOD; } else if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsTermIndex(beforeStr, utilityConfiguration.InConnectorRegex)) { var match = utilityConfiguration.LaterRegex.Match(afterStr); var swift = 0; // Handle cases like "3 days after tomorrow" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), true); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.AFTER_MOD; } if (resultDateTime != referenceTime) { if (mode.Equals(AgoLaterMode.Date)) { ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}"; } else if (mode.Equals(AgoLaterMode.DateTime)) { ret.Timex = $"{DateTimeFormatUtil.LuisDateTime(resultDateTime)}"; } ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { durationParseResult }; ret.Success = true; } return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refTime) { var referenceTime = refTime; DateTimeParseResult pr = null; var originText = er.Text; if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0) { er.Text = MatchingUtil.PreProcessTextRemoveSuperfluousWords(er.Text, Config.SuperfluousWordMatcher, out var _); er.Length += er.Text.Length - originText.Length; } bool hasBefore = false, hasAfter = false, hasSince = false, hasAround = false, hasEqual = false, hasDateAfter = false; // "InclusiveModifier" means MOD should include the start/end time // For example, cases like "on or later than", "earlier than or in" have inclusive modifier var hasInclusiveModifier = false; var matchIsAfter = false; var modStr = string.Empty; // Analyze and process modifiers // Push, save the MOD string if (er.Metadata != null && er.Metadata.HasMod) { var beforeMatch = Config.BeforeRegex.MatchBegin(er.Text, trim: true); var afterMatch = Config.AfterRegex.MatchBegin(er.Text, trim: true); var sinceMatch = Config.SinceRegex.MatchBegin(er.Text, trim: true); var aroundMatch = Config.AroundRegex.MatchBegin(er.Text, trim: true); var equalMatch = Config.EqualRegex.MatchBegin(er.Text, trim: true); // check also after match if (this.Config.CheckBothBeforeAfter && er.Data != null && er.Data.Equals(Constants.HAS_MOD)) { if (!beforeMatch.Success) { beforeMatch = Config.BeforeRegex.MatchEnd(er.Text, trim: true); matchIsAfter = matchIsAfter || beforeMatch.Success; } if (!afterMatch.Success) { afterMatch = Config.AfterRegex.MatchEnd(er.Text, trim: true); matchIsAfter = matchIsAfter || afterMatch.Success; } if (!sinceMatch.Success) { sinceMatch = Config.SinceRegex.MatchEnd(er.Text, trim: true); matchIsAfter = matchIsAfter || sinceMatch.Success; } if (!aroundMatch.Success) { aroundMatch = Config.AroundRegex.MatchEnd(er.Text, trim: true); matchIsAfter = matchIsAfter || aroundMatch.Success; } if (!equalMatch.Success) { equalMatch = Config.EqualRegex.MatchEnd(er.Text, trim: true); matchIsAfter = matchIsAfter || equalMatch.Success; } } if (beforeMatch.Success) { hasBefore = true; er.Start += matchIsAfter ? 0 : beforeMatch.Length; er.Length -= beforeMatch.Length; er.Text = matchIsAfter ? er.Text.Substring(0, (int)er.Length) : er.Text.Substring(beforeMatch.Length); modStr = beforeMatch.Value; if (!string.IsNullOrEmpty(beforeMatch.Groups[Constants.IncludeGroupName].Value)) { hasInclusiveModifier = true; } } else if (afterMatch.Success) { hasAfter = true; er.Start += matchIsAfter ? 0 : afterMatch.Length; er.Length -= afterMatch.Length; er.Text = matchIsAfter ? er.Text.Substring(0, (int)er.Length) : er.Text.Substring(afterMatch.Length); modStr = afterMatch.Value; if (!string.IsNullOrEmpty(afterMatch.Groups[Constants.IncludeGroupName].Value)) { hasInclusiveModifier = true; } } else if (sinceMatch.Success) { hasSince = true; er.Start += matchIsAfter ? 0 : sinceMatch.Length; er.Length -= sinceMatch.Length; er.Text = matchIsAfter ? er.Text.Substring(0, (int)er.Length) : er.Text.Substring(sinceMatch.Length); modStr = sinceMatch.Value; } else if (aroundMatch.Success) { hasAround = true; er.Start += matchIsAfter ? 0 : aroundMatch.Length; er.Length -= aroundMatch.Length; er.Text = matchIsAfter ? er.Text.Substring(0, (int)er.Length) : er.Text.Substring(aroundMatch.Length); modStr = aroundMatch.Value; } else if (equalMatch.Success) { hasEqual = true; er.Start += matchIsAfter ? 0 : equalMatch.Length; er.Length -= equalMatch.Length; er.Text = matchIsAfter ? er.Text.Substring(0, (int)er.Length) : er.Text.Substring(equalMatch.Length); modStr = equalMatch.Value; } else if ((er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD, StringComparison.Ordinal) && Config.YearRegex.Match(er.Text).Success) || er.Type.Equals(Constants.SYS_DATETIME_DATE, StringComparison.Ordinal) || er.Type.Equals(Constants.SYS_DATETIME_TIME, StringComparison.Ordinal)) { // This has to be put at the end of the if, or cases like "before 2012" and "after 2012" would fall into this // 2012 or after/above // 3 pm or later var match = Config.SuffixAfter.MatchEnd(er.Text, trim: true); if (match.Success) { hasDateAfter = true; er.Length -= match.Length; er.Text = er.Text.Substring(0, er.Length ?? 0); modStr = match.Value; } } } // Parse extracted datetime mention pr = ParseResult(er, referenceTime); if (pr == null) { return(null); } // Apply processed modifiers // Pop, restore the MOD string if (hasBefore && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= matchIsAfter ? 0 : modStr.Length; pr.Text = matchIsAfter ? pr.Text + modStr : modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = CombineMod(val.Mod, !hasInclusiveModifier ? Constants.BEFORE_MOD : Constants.UNTIL_MOD); pr.Value = val; } if (hasAfter && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= matchIsAfter ? 0 : modStr.Length; pr.Text = matchIsAfter ? pr.Text + modStr : modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; if (!hasInclusiveModifier) { val.Mod = CombineMod(val.Mod, Constants.AFTER_MOD); } else { val.Mod = CombineMod(val.Mod, Constants.SINCE_MOD); } pr.Value = val; } if (hasSince && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= matchIsAfter ? 0 : modStr.Length; pr.Text = matchIsAfter ? pr.Text + modStr : modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = CombineMod(val.Mod, Constants.SINCE_MOD); pr.Value = val; } if (hasAround && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= matchIsAfter ? 0 : modStr.Length; pr.Text = matchIsAfter ? pr.Text + modStr : modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = CombineMod(val.Mod, Constants.APPROX_MOD); pr.Value = val; } if (hasEqual && pr.Value != null) { pr.Length += modStr.Length; pr.Start -= matchIsAfter ? 0 : modStr.Length; pr.Text = matchIsAfter ? pr.Text + modStr : modStr + pr.Text; } if (hasDateAfter && pr.Value != null) { pr.Length += modStr.Length; pr.Text = pr.Text + modStr; var val = (DateTimeResolutionResult)pr.Value; val.Mod = CombineMod(val.Mod, Constants.SINCE_MOD); pr.Value = val; hasSince = true; } // For cases like "3 pm or later on monday" if (pr.Value != null && Config.SuffixAfter.Match(pr.Text)?.Index != 0 && pr.Type.Equals(Constants.SYS_DATETIME_DATETIME, StringComparison.Ordinal) && !this.Config.CheckBothBeforeAfter) { var val = (DateTimeResolutionResult)pr.Value; val.Mod = CombineMod(val.Mod, Constants.SINCE_MOD); pr.Value = val; hasSince = true; } if ((Config.Options & DateTimeOptions.SplitDateAndTime) != 0 && ((DateTimeResolutionResult)pr?.Value)?.SubDateTimeEntities != null) { pr.Value = DateTimeResolutionForSplit(pr); } else { var hasRangeChangingMod = hasBefore || hasAfter || hasSince; if (pr.Value != null) { ((DateTimeResolutionResult)pr.Value).HasRangeChangingMod = hasRangeChangingMod; } pr = SetParseResult(pr, hasRangeChangingMod); } // In this version, ExperimentalMode only cope with the "IncludePeriodEnd" case if ((this.Config.Options & DateTimeOptions.ExperimentalMode) != 0) { if (pr?.Metadata != null && pr.Metadata.PossiblyIncludePeriodEnd) { pr = SetInclusivePeriodEnd(pr); } } if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0) { if (pr != null) { pr.Length += originText.Length - pr.Text.Length; pr.Text = originText; } } return(pr); }
private static DateTimeResolutionResult GetAgoLaterResult( DateTimeParseResult durationParseResult, string afterStr, string beforeStr, DateObject referenceTime, IParser numberParser, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode, SwiftDayDelegate swiftDay) { var ret = new DateTimeResolutionResult(); var resultDateTime = referenceTime; var timex = durationParseResult.TimexStr; if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.MORE_THAN_MOD) { ret.Mod = Constants.MORE_THAN_MOD; } else if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.LESS_THAN_MOD) { ret.Mod = Constants.LESS_THAN_MOD; } int swift = 0; bool isMatch = false, isLater = false; string dayStr = null; var agoLaterRegexes = new List <(Regex, string)> { (utilityConfiguration.AgoRegex, "ago"), (utilityConfiguration.LaterRegex, "later"), }; // AgoRegex and LaterRegex cases foreach (var regex in agoLaterRegexes) { // Match in afterStr if (MatchingUtil.ContainsAgoLaterIndex(afterStr, regex.Item1, inSuffix: true)) { isMatch = true; isLater = regex.Item2 == "later" ? true : false; var match = regex.Item1.Match(afterStr); dayStr = match.Groups["day"].Value; } if (utilityConfiguration.CheckBothBeforeAfter) { // Match split between beforeStr and afterStr if (string.IsNullOrEmpty(dayStr) && isMatch) { var match = regex.Item1.Match(beforeStr + " " + afterStr); dayStr = match.Groups["day"].Value; } // Match in beforeStr if (string.IsNullOrEmpty(dayStr) && MatchingUtil.ContainsAgoLaterIndex(beforeStr, regex.Item1, inSuffix: false)) { isMatch = true; isLater = regex.Item2 == "later" ? true : false; var match = regex.Item1.Match(beforeStr); dayStr = match.Groups["day"].Value; } } if (isMatch) { break; } } // InConnectorRegex cases if (!isMatch) { if (MatchingUtil.ContainsTermIndex(beforeStr, utilityConfiguration.InConnectorRegex)) { // Match in afterStr isMatch = isLater = true; var match = utilityConfiguration.LaterRegex.Match(afterStr); dayStr = match.Groups["day"].Value; } else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.InConnectorRegex, inSuffix: true)) { // Match in beforeStr isMatch = isLater = true; var match = utilityConfiguration.LaterRegex.Match(beforeStr); dayStr = match.Groups["day"].Value; } } if (isMatch) { // Handle cases like "3 days before yesterday", "3 days after tomorrow" if (!string.IsNullOrEmpty(dayStr)) { swift = swiftDay(dayStr); } if (isLater) { var yearMatch = utilityConfiguration.SinceYearSuffixRegex.Match(afterStr); if (yearMatch.Success) { var yearString = yearMatch.Groups[Constants.YearGroupName].Value; var yearEr = new ExtractResult { Text = yearString }; var year = Convert.ToInt32((double)(numberParser.Parse(yearEr).Value ?? 0)); referenceTime = DateObject.MinValue.SafeCreateFromValue(year, 1, 1); } } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), isLater ? true : false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = isLater ? Constants.AFTER_MOD : Constants.BEFORE_MOD; } if (resultDateTime != referenceTime) { if (mode.Equals(AgoLaterMode.Date)) { ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}"; } else if (mode.Equals(AgoLaterMode.DateTime)) { ret.Timex = $"{DateTimeFormatUtil.LuisDateTime(resultDateTime)}"; } ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { durationParseResult }; ret.Success = true; } return(ret); }
public static List <Token> ExtractorDurationWithBeforeAndAfter(string text, ExtractResult er, List <Token> ret, IDateTimeUtilityConfiguration utilityConfiguration) { var pos = (int)er.Start + (int)er.Length; if (pos <= text.Length) { var afterString = text.Substring(pos); var beforeString = text.Substring(0, (int)er.Start); var isTimeDuration = utilityConfiguration.TimeUnitRegex.Match(er.Text).Success; if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.AgoRegex, out var index)) { // We don't support cases like "5 minutes from today" for now // Cases like "5 minutes ago" or "5 minutes from now" are supported // Cases like "2 days before today" or "2 weeks from today" are also supported var isDayMatchInAfterString = utilityConfiguration.AgoRegex.Match(afterString).Groups["day"].Success; if (!(isTimeDuration && isDayMatchInAfterString)) { ret.Add(new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index)); } if (utilityConfiguration.CheckBothBeforeAfter && !isDayMatchInAfterString) { // check if regex match is split between beforeString and afterString string beforeAfterStr = beforeString + afterString.Substring(0, index); if (MatchingUtil.GetAgoLaterIndexInBeforeString(beforeAfterStr, utilityConfiguration.AgoRegex, out var indexStart)) { isDayMatchInAfterString = utilityConfiguration.AgoRegex.Match(beforeAfterStr).Groups["day"].Success; if (isDayMatchInAfterString && !(isTimeDuration && isDayMatchInAfterString)) { ret.Add(new Token(indexStart, (er.Start + er.Length ?? 0) + index)); } } } } else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.GetAgoLaterIndexInBeforeString(beforeString, utilityConfiguration.AgoRegex, out index)) { // Check also beforeString var isDayMatchInBeforeString = utilityConfiguration.AgoRegex.Match(beforeString).Groups["day"].Success; if (!(isTimeDuration && isDayMatchInBeforeString)) { ret.Add(new Token(index, (er.Start + er.Length ?? 0) + index)); } } else if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.LaterRegex, out index) || (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.GetAgoLaterIndexInBeforeString(beforeString, utilityConfiguration.LaterRegex, out index))) { Token tokAfter = null, tokBefore = null; if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.LaterRegex, out index)) { var isDayMatchInAfterString = utilityConfiguration.LaterRegex.Match(afterString).Groups["day"].Success; if (!(isTimeDuration && isDayMatchInAfterString)) { tokAfter = new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index); } } // Check also beforeString if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.GetAgoLaterIndexInBeforeString(beforeString, utilityConfiguration.LaterRegex, out index)) { var isDayMatchInBeforeString = utilityConfiguration.LaterRegex.Match(beforeString).Groups["day"].Success; if (!(isTimeDuration && isDayMatchInBeforeString)) { tokBefore = new Token(index, er.Start + er.Length ?? 0); } } if (tokAfter != null && tokBefore != null && tokBefore.Start + tokBefore.Length > tokAfter.Start) { // merge overlapping tokens ret.Add(new Token(tokBefore.Start, tokAfter.Start + tokAfter.Length - tokBefore.Start)); } else if (tokAfter != null) { ret.Add(tokAfter); } else if (tokBefore != null) { ret.Add(tokBefore); } } else if (MatchingUtil.GetTermIndex(beforeString, utilityConfiguration.InConnectorRegex, out index)) { // For range unit like "week, month, year", it should output dateRange or datetimeRange if (!utilityConfiguration.RangeUnitRegex.IsMatch(er.Text)) { if (er.Start != null && er.Length != null && (int)er.Start >= index) { ret.Add(new Token((int)er.Start - index, (int)er.Start + (int)er.Length)); } } } else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.InConnectorRegex, out index)) { // Check also afterString // For range unit like "week, month, year", it should output dateRange or datetimeRange if (!utilityConfiguration.RangeUnitRegex.IsMatch(er.Text)) { if (er.Start != null && er.Length != null) { ret.Add(new Token((int)er.Start, (int)er.Start + (int)er.Length + index)); } } } else if (MatchingUtil.GetTermIndex(beforeString, utilityConfiguration.WithinNextPrefixRegex, out index)) { // For range unit like "week, month, year, day, second, minute, hour", it should output dateRange or datetimeRange if (!utilityConfiguration.DateUnitRegex.IsMatch(er.Text) && !utilityConfiguration.TimeUnitRegex.IsMatch(er.Text)) { if (er.Start != null && er.Length != null && (int)er.Start >= index) { ret.Add(new Token((int)er.Start - index, (int)er.Start + (int)er.Length)); } } } else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.WithinNextPrefixRegex, out index)) { // Check also afterString // For range unit like "week, month, year, day, second, minute, hour", it should output dateRange or datetimeRange if (!utilityConfiguration.DateUnitRegex.IsMatch(er.Text) && !utilityConfiguration.TimeUnitRegex.IsMatch(er.Text)) { if (er.Start != null && er.Length != null) { ret.Add(new Token((int)er.Start, (int)er.Start + (int)er.Length + index)); } } } } return(ret); }
private IEnumerable <Token> MatchLocationTimes(string text, List <Token> tokens, string originalText, bool reIndex) { var ret = new List <Token>(); if (config.LocationTimeSuffixRegex == null) { return(ret); } var timeMatch = config.LocationTimeSuffixRegex.Matches(text); // Before calling a Find() in location matcher, check if all the matched suffixes by // LocationTimeSuffixRegex are already inside tokens extracted by TimeZone matcher. // If so, don't call the Find() as they have been extracted by TimeZone matcher, otherwise, call it. bool isAllSuffixInsideTokens = true; foreach (Match match in timeMatch) { bool isInside = false; foreach (Token token in tokens) { if (token.Start <= match.Index && token.End >= match.Index + match.Length) { isInside = true; break; } } if (!isInside) { isAllSuffixInsideTokens = false; } if (!isAllSuffixInsideTokens) { break; } } if (timeMatch.Count != 0 && !isAllSuffixInsideTokens) { var lastMatchIndex = timeMatch[timeMatch.Count - 1].Index; var matches = config.LocationMatcher.Find(text.Substring(0, lastMatchIndex)); var locationMatches = MatchingUtil.RemoveSubMatches(matches); if (reIndex) { foreach (var locMatch in locationMatches) { locMatch.Start = originalText.IndexOf(locMatch.CanonicalValues.FirstOrDefault(), locMatch.Start, StringComparison.Ordinal); } } var i = 0; foreach (Match match in timeMatch) { var hasCityBefore = false; var index = match.Index; if (reIndex) { index = originalText.IndexOf(match.Value, match.Index, StringComparison.Ordinal); } while (i < locationMatches.Count && locationMatches[i].End <= index) { hasCityBefore = true; i++; if (i == locationMatches.Count) { break; } } if (hasCityBefore && locationMatches[i - 1].End == index) { ret.Add(new Token(locationMatches[i - 1].Start, index + match.Length)); } if (i == locationMatches.Count) { break; } } } return(ret); }
public static List <Token> ExtractorDurationWithBeforeAndAfter(string text, ExtractResult er, List <Token> ret, IDateTimeUtilityConfiguration utilityConfiguration) { var pos = (int)er.Start + (int)er.Length; if (pos <= text.Length) { var afterString = text.Substring(pos); var beforeString = text.Substring(0, (int)er.Start); var isTimeDuration = utilityConfiguration.TimeUnitRegex.Match(er.Text).Success; int index; bool isMatch = false; var agoLaterRegexes = new List <Regex> { utilityConfiguration.AgoRegex, utilityConfiguration.LaterRegex, }; foreach (var regex in agoLaterRegexes) { Token tokAfter = null, tokBefore = null; bool isDayMatch = false; // Check afterString if (MatchingUtil.GetAgoLaterIndex(afterString, regex, out index, inSuffix: true)) { // We don't support cases like "5 minutes from today" for now // Cases like "5 minutes ago" or "5 minutes from now" are supported // Cases like "2 days before today" or "2 weeks from today" are also supported isDayMatch = regex.Match(afterString).Groups["day"].Success; if (!(isTimeDuration && isDayMatch)) { tokAfter = new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index); isMatch = true; } } if (utilityConfiguration.CheckBothBeforeAfter) { // Check if regex match is split between beforeString and afterString if (!isDayMatch && isMatch) { string beforeAfterStr = beforeString + afterString.Substring(0, index); var isRangeMatch = utilityConfiguration.RangePrefixRegex.MatchBegin(afterString.Substring(index), trim: true).Success; if (!isRangeMatch && MatchingUtil.GetAgoLaterIndex(beforeAfterStr, regex, out var indexStart, inSuffix: false)) { isDayMatch = regex.Match(beforeAfterStr).Groups["day"].Success; if (isDayMatch && !(isTimeDuration && isDayMatch)) { ret.Add(new Token(indexStart, (er.Start + er.Length ?? 0) + index)); isMatch = true; } } } // Check also beforeString if (MatchingUtil.GetAgoLaterIndex(beforeString, regex, out index, inSuffix: false)) { isDayMatch = regex.Match(beforeString).Groups["day"].Success; if (!(isTimeDuration && isDayMatch)) { tokBefore = new Token(index, er.Start + er.Length ?? 0); isMatch = true; } } } if (tokAfter != null && tokBefore != null && tokBefore.Start + tokBefore.Length > tokAfter.Start) { // Merge overlapping tokens ret.Add(new Token(tokBefore.Start, tokAfter.Start + tokAfter.Length - tokBefore.Start)); } else if (tokAfter != null) { ret.Add(tokAfter); } else if (tokBefore != null) { ret.Add(tokBefore); } if (isMatch) { break; } } if (!isMatch) { var inWithinRegexes = new List <(Regex, List <Regex>)> { (utilityConfiguration.InConnectorRegex, new List <Regex> { utilityConfiguration.RangeUnitRegex }), (utilityConfiguration.WithinNextPrefixRegex, new List <Regex> { utilityConfiguration.DateUnitRegex, utilityConfiguration.TimeUnitRegex }), }; foreach (var regex in inWithinRegexes) { bool isMatchAfter = false; if (MatchingUtil.GetTermIndex(beforeString, regex.Item1, out index)) { isMatch = true; } else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.GetAgoLaterIndex(afterString, regex.Item1, out index, inSuffix: true)) { // Check also afterString isMatch = isMatchAfter = true; } if (isMatch) { // For InConnectorRegex and range unit like "week, month, year", it should output dateRange or datetimeRange // For WithinNextPrefixRegex and range unit like "week, month, year, day, second, minute, hour", it should output dateRange or datetimeRange bool isUnitMatch = false; foreach (var unitRegex in regex.Item2) { isUnitMatch = isUnitMatch || unitRegex.IsMatch(er.Text); } if (!isUnitMatch) { if (er.Start != null && er.Length != null && ((int)er.Start >= index || isMatchAfter)) { int start = (int)er.Start - (!isMatchAfter ? index : 0); int end = (int)er.Start + (int)er.Length + (isMatchAfter ? index : 0); ret.Add(new Token(start, end)); } } break; } } } } return(ret); }
// Check every integers and ordinal number for date private List <Token> NumberWithMonth(string text, DateObject reference) { var ret = new List <Token>(); var er = this.Config.OrdinalExtractor.Extract(text); er.AddRange(this.Config.IntegerExtractor.Extract(text)); foreach (var result in er) { var parsed = int.TryParse((this.Config.NumberParser.Parse(result).Value ?? 0).ToString(), out int num); if (!parsed || (num < 1 || num > 31)) { continue; } if (result.Start >= 0) { // Handling cases like '(Monday,) Jan twenty two' var prefixStr = text.Substring(0, result.Start ?? 0); // Check that the extracted number is not part of a decimal number, time expression or currency // (e.g. '123.24', '12:24', '$12') if (MatchingUtil.IsInvalidDayNumberPrefix(prefixStr)) { continue; } var match = this.Config.MonthEnd.Match(prefixStr); if (match.Success) { var startIndex = match.Index; var endIndex = match.Index + match.Length + (result.Length ?? 0); ExtendWithWeekdayAndYear( ref startIndex, ref endIndex, Config.MonthOfYear.GetValueOrDefault(match.Groups["month"].Value, reference.Month), num, text, reference); ret.Add(new Token(startIndex, endIndex)); continue; } // Handling cases like 'for the 25th' var matches = this.Config.ForTheRegex.Matches(text); bool isFound = false; foreach (Match matchCase in matches) { if (matchCase.Success) { var ordinalNum = matchCase.Groups["DayOfMonth"].Value; if (ordinalNum == result.Text) { var endLength = 0; if (matchCase.Groups["end"].Value.Length > 0) { endLength = matchCase.Groups["end"].Value.Length; } ret.Add(new Token(matchCase.Index, matchCase.Index + matchCase.Length - endLength)); isFound = true; } } } if (isFound) { continue; } // Handling cases like 'Thursday the 21st', which both 'Thursday' and '21st' refer to a same date matches = this.Config.WeekDayAndDayOfMonthRegex.Matches(text); foreach (Match matchCase in matches) { if (matchCase.Success) { var ordinalNum = matchCase.Groups["DayOfMonth"].Value; if (ordinalNum == result.Text && matchCase.Groups["DayOfMonth"].Index == result.Start) { // Get week of day for the ordinal number which is regarded as a date of reference month var date = DateObject.MinValue.SafeCreateFromValue(reference.Year, reference.Month, num); var numWeekDayInt = (int)date.DayOfWeek; // Get week day from text directly, compare it with the weekday generated above // to see whether they refer to the same week day var extractedWeekDayStr = matchCase.Groups["weekday"].Value; if (!date.Equals(DateObject.MinValue) && numWeekDayInt == Config.DayOfWeek[extractedWeekDayStr]) { ret.Add(new Token(matchCase.Index, matchCase.Index + matchCase.Length)); isFound = true; } } } } if (isFound) { continue; } // Handling cases like 'Monday 21', which both 'Monday' and '21' refer to the same date // The year of expected date can be different to the year of referenceDate. matches = this.Config.WeekDayAndDayRegex.Matches(text); foreach (Match matchCase in matches) { if (matchCase.Success) { var matchLength = result.Start + result.Length - matchCase.Index; if (matchLength == matchCase.Length) { // check if day number is compatible with reference month if (DateObjectExtension.IsValidDate(reference.Year, reference.Month, num) || !this.Config.CheckBothBeforeAfter) { ret.Add(new Token(matchCase.Index, result.Start + result.Length ?? 0)); isFound = true; } } } } if (isFound) { continue; } // Handling cases like '20th of next month' var suffixStr = text.Substring(result.Start + result.Length ?? 0); var beginMatch = this.Config.RelativeMonthRegex.MatchBegin(suffixStr.Trim(), trim: true); if (beginMatch.Success && beginMatch.Index == 0) { var spaceLen = suffixStr.Length - suffixStr.Trim().Length; var resStart = result.Start; var resEnd = resStart + result.Length + spaceLen + beginMatch.Length; // Check if prefix contains 'the', include it if any var prefix = text.Substring(0, resStart ?? 0); var prefixMatch = this.Config.PrefixArticleRegex.Match(prefix); if (prefixMatch.Success) { resStart = prefixMatch.Index; } ret.Add(new Token(resStart ?? 0, resEnd ?? 0)); } // Handling cases like 'second Sunday' suffixStr = text.Substring(result.Start + result.Length ?? 0); beginMatch = this.Config.WeekDayRegex.MatchBegin(suffixStr.Trim(), trim: true); if (beginMatch.Success && num >= 1 && num <= 5 && result.Type.Equals(Number.Constants.SYS_NUM_ORDINAL, StringComparison.Ordinal) && !this.Config.WeekDayRegex.IsExactMatch(result.Text, trim: true)) { var weekDayStr = beginMatch.Groups["weekday"].Value; if (this.Config.DayOfWeek.ContainsKey(weekDayStr)) { var spaceLen = suffixStr.Length - suffixStr.Trim().Length; ret.Add(new Token(result.Start ?? 0, result.Start + result.Length + spaceLen + beginMatch.Length ?? 0)); } } } // For cases like "I'll go back twenty second of June" if (result.Start + result.Length < text.Length) { var afterStr = text.Substring(result.Start + result.Length ?? 0); var match = this.Config.OfMonth.Match(afterStr); if (match.Success) { var startIndex = result.Start ?? 0; var endIndex = (result.Start + result.Length ?? 0) + match.Length; ExtendWithWeekdayAndYear(ref startIndex, ref endIndex, Config.MonthOfYear.GetValueOrDefault(match.Groups["month"].Value, reference.Month), num, text, reference); ret.Add(new Token(startIndex, endIndex)); } } } return(ret); }
public DateTimeParseResult Parse(ExtractResult er, DateObject refTime) { var referenceTime = refTime; DateTimeParseResult pr = null; var originText = er.Text; if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0) { er.Text = MatchingUtil.PreProcessTextRemoveSuperfluousWords(er.Text, Config.SuperfluousWordMatcher, out var _); er.Length += er.Text.Length - originText.Length; } // Push, save the MOD string bool hasBefore = false, hasAfter = false, hasSince = false, hasAround = false, hasDateAfter = false; // "InclusiveModifier" means MOD should include the start/end time // For example, cases like "on or later than", "earlier than or in" have inclusive modifier bool hasInclusiveModifier = false; var modStr = string.Empty; var beforeMatch = Config.BeforeRegex.MatchBegin(er.Text, trim: true); var afterMatch = Config.AfterRegex.MatchBegin(er.Text, trim: true); var sinceMatch = Config.SinceRegex.MatchBegin(er.Text, trim: true); var aroundMatch = Config.AroundRegex.MatchBegin(er.Text, trim: true); if (beforeMatch.Success) { hasBefore = true; er.Start += beforeMatch.Length; er.Length -= beforeMatch.Length; er.Text = er.Text.Substring(beforeMatch.Length); modStr = beforeMatch.Value; if (!string.IsNullOrEmpty(beforeMatch.Groups["include"].Value)) { hasInclusiveModifier = true; } } else if (afterMatch.Success) { hasAfter = true; er.Start += afterMatch.Length; er.Length -= afterMatch.Length; er.Text = er.Text.Substring(afterMatch.Length); modStr = afterMatch.Value; if (!string.IsNullOrEmpty(afterMatch.Groups["include"].Value)) { hasInclusiveModifier = true; } } else if (sinceMatch.Success) { hasSince = true; er.Start += sinceMatch.Length; er.Length -= sinceMatch.Length; er.Text = er.Text.Substring(sinceMatch.Length); modStr = sinceMatch.Value; } else if (aroundMatch.Success) { hasAround = true; er.Start += aroundMatch.Length; er.Length -= aroundMatch.Length; er.Text = er.Text.Substring(aroundMatch.Length); modStr = aroundMatch.Value; } else if ((er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD) && Config.YearRegex.Match(er.Text).Success) || er.Type.Equals(Constants.SYS_DATETIME_DATE)) { // This has to be put at the end of the if, or cases like "before 2012" and "after 2012" would fall into this // 2012 or after/above var match = Config.DateAfter.MatchEnd(er.Text, trim: true); if (match.Success) { hasDateAfter = true; er.Length -= match.Length; er.Text = er.Text.Substring(0, er.Length ?? 0); modStr = match.Value; } } if (er.Type.Equals(Constants.SYS_DATETIME_DATE)) { pr = this.Config.DateParser.Parse(er, referenceTime); if (pr.Value == null) { pr = Config.HolidayParser.Parse(er, referenceTime); } } else if (er.Type.Equals(Constants.SYS_DATETIME_TIME)) { pr = this.Config.TimeParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIME)) { pr = this.Config.DateTimeParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD)) { pr = this.Config.DatePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_TIMEPERIOD)) { pr = this.Config.TimePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIMEPERIOD)) { pr = this.Config.DateTimePeriodParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DURATION)) { pr = this.Config.DurationParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_SET)) { pr = this.Config.SetParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIMEALT)) { pr = this.Config.DateTimeAltParser.Parse(er, referenceTime); } else if (er.Type.Equals(Constants.SYS_DATETIME_TIMEZONE)) { if ((Config.Options & DateTimeOptions.EnablePreview) != 0) { pr = this.Config.TimeZoneParser.Parse(er, referenceTime); } } else { return(null); } // Pop, restore the MOD string if (hasBefore && (pr != null && pr.Value != null)) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; if (!hasInclusiveModifier) { val.Mod = Constants.BEFORE_MOD; } else { val.Mod = Constants.UNTIL_MOD; } pr.Value = val; } if (hasAfter && (pr != null && pr.Value != null)) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; if (!hasInclusiveModifier) { val.Mod = Constants.AFTER_MOD; } else { val.Mod = Constants.SINCE_MOD; } pr.Value = val; } if (hasSince && (pr != null && pr.Value != null)) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.SINCE_MOD; pr.Value = val; } if (hasAround && (pr != null && pr.Value != null)) { pr.Length += modStr.Length; pr.Start -= modStr.Length; pr.Text = modStr + pr.Text; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.APPROX_MOD; pr.Value = val; } if (hasDateAfter && (pr != null && pr.Value != null)) { pr.Length += modStr.Length; pr.Text = pr.Text + modStr; var val = (DateTimeResolutionResult)pr.Value; val.Mod = Constants.SINCE_MOD; pr.Value = val; hasSince = true; } if ((Config.Options & DateTimeOptions.SplitDateAndTime) != 0 && ((DateTimeResolutionResult)pr?.Value)?.SubDateTimeEntities != null) { if (pr != null) { pr.Value = DateTimeResolutionForSplit(pr); } } else { var hasModifier = hasBefore || hasAfter || hasSince; pr = SetParseResult(pr, hasModifier); } // In this version, ExperimentalMode only cope with the "IncludePeriodEnd" case if ((this.Config.Options & DateTimeOptions.ExperimentalMode) != 0) { if (pr?.Metadata != null && pr.Metadata.PossiblyIncludePeriodEnd) { pr = SetInclusivePeriodEnd(pr); } } if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0) { pr.Length += originText.Length - pr.Text.Length; pr.Text = originText; } return(pr); }
private static DateTimeResolutionResult GetAgoLaterResult( DateTimeParseResult durationParseResult, string afterStr, string beforeStr, DateObject referenceTime, IParser numberParser, IDateTimeUtilityConfiguration utilityConfiguration, AgoLaterMode mode, SwiftDayDelegate swiftDay) { var ret = new DateTimeResolutionResult(); var resultDateTime = referenceTime; var timex = durationParseResult.TimexStr; if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.MORE_THAN_MOD) { ret.Mod = Constants.MORE_THAN_MOD; } else if (((DateTimeResolutionResult)durationParseResult.Value).Mod == Constants.LESS_THAN_MOD) { ret.Mod = Constants.LESS_THAN_MOD; } if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.AgoRegex)) { var match = utilityConfiguration.AgoRegex.Match(afterStr); var swift = 0; // Handle cases like "3 days before yesterday" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } else if (utilityConfiguration.CheckBothBeforeAfter && match.Success && !MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.AgoRegex)) { match = utilityConfiguration.AgoRegex.Match(beforeStr + " " + afterStr); if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.BEFORE_MOD; } else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.AgoRegex)) { var match = utilityConfiguration.AgoRegex.Match(beforeStr); var swift = 0; // Handle cases like "3 days before yesterday" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), false); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.BEFORE_MOD; } else if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsTermIndex(beforeStr, utilityConfiguration.InConnectorRegex) || (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.LaterRegex))) { var match = utilityConfiguration.LaterRegex.Match(afterStr); var swift = 0; if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.LaterRegex) && string.IsNullOrEmpty(match.Groups["day"].Value)) { match = utilityConfiguration.LaterRegex.Match(beforeStr); } // Handle cases like "3 days after tomorrow" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } var yearMatch = utilityConfiguration.SinceYearSuffixRegex.Match(afterStr); if (yearMatch.Success) { var yearString = yearMatch.Groups[Constants.YearGroupName].Value; var yearEr = new ExtractResult { Text = yearString }; var year = Convert.ToInt32((double)(numberParser.Parse(yearEr).Value ?? 0)); referenceTime = DateObject.MinValue.SafeCreateFromValue(year, 1, 1); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), true); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.AFTER_MOD; } else if (utilityConfiguration.CheckBothBeforeAfter && (MatchingUtil.ContainsAgoLaterIndexInBeforeString(beforeStr, utilityConfiguration.LaterRegex) || MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.InConnectorRegex) || MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex))) { // Check also beforeStr var match = utilityConfiguration.LaterRegex.Match(beforeStr); var swift = 0; if (MatchingUtil.ContainsAgoLaterIndex(afterStr, utilityConfiguration.LaterRegex) && string.IsNullOrEmpty(match.Groups["day"].Value)) { match = utilityConfiguration.LaterRegex.Match(beforeStr); } // Handle cases like "3 days after tomorrow" if (match.Success && !string.IsNullOrEmpty(match.Groups["day"].Value)) { swift = swiftDay(match.Groups["day"].Value); } var yearMatch = utilityConfiguration.SinceYearSuffixRegex.Match(beforeStr); if (yearMatch.Success) { var yearString = yearMatch.Groups[Constants.YearGroupName].Value; var yearEr = new ExtractResult { Text = yearString }; var year = Convert.ToInt32((double)(numberParser.Parse(yearEr).Value ?? 0)); referenceTime = DateObject.MinValue.SafeCreateFromValue(year, 1, 1); } resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceTime.AddDays(swift), true); ((DateTimeResolutionResult)durationParseResult.Value).Mod = Constants.AFTER_MOD; } if (resultDateTime != referenceTime) { if (mode.Equals(AgoLaterMode.Date)) { ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}"; } else if (mode.Equals(AgoLaterMode.DateTime)) { ret.Timex = $"{DateTimeFormatUtil.LuisDateTime(resultDateTime)}"; } ret.FutureValue = ret.PastValue = resultDateTime; ret.SubDateTimeEntities = new List <object> { durationParseResult }; ret.Success = true; } return(ret); }