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);
        }
Example #2
0
        private DateTimeResolutionResult ParseDuration(string text, DateObject referenceDate)
        {
            var        ret = new DateTimeResolutionResult();
            DateObject beginDate;
            var        endDate       = beginDate = referenceDate;
            string     timex         = string.Empty;
            bool       restNowSunday = false;

            var ers = config.DurationExtractor.Extract(text, referenceDate);

            if (ers.Count == 1)
            {
                var pr        = config.DurationParser.Parse(ers[0]);
                var beforeStr = text.Substring(0, pr.Start ?? 0).Trim().ToLowerInvariant();
                var afterStr  = text.Substring((pr.Start ?? 0) + (pr.Length ?? 0)).Trim().ToLowerInvariant();
                var mod       = "";

                if (pr.Value != null)
                {
                    var durationResult = (DateTimeResolutionResult)pr.Value;

                    if (string.IsNullOrEmpty(durationResult.Timex))
                    {
                        return(ret);
                    }

                    var prefixMatch = config.PastRegex.Match(beforeStr);
                    if (prefixMatch.Success)
                    {
                        mod       = TimeTypeConstants.beforeMod;
                        beginDate = DurationParsingUtil.ShiftDateTime(durationResult.Timex, endDate, false);
                    }
                    else
                    {
                        var suffixMatch = config.PastRegex.Match(afterStr);
                        if (suffixMatch.Success)
                        {
                            mod       = TimeTypeConstants.beforeMod;
                            beginDate = DurationParsingUtil.ShiftDateTime(durationResult.Timex, endDate, false);
                        }
                    }

                    prefixMatch = config.FutureRegex.Match(beforeStr);
                    if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length)
                    {
                        mod = TimeTypeConstants.afterMod;

                        // For future the beginDate should add 1 first
                        beginDate = referenceDate.AddDays(1);
                        endDate   = DurationParsingUtil.ShiftDateTime(durationResult.Timex, beginDate, true);
                    }

                    // Handle the "in two weeks" case which means the second week
                    prefixMatch = config.InConnectorRegex.Match(beforeStr);
                    if (prefixMatch.Success && prefixMatch.Length == beforeStr.Length &&
                        !DurationParsingUtil.IsMultipleDuration(durationResult.Timex))
                    {
                        mod = TimeTypeConstants.afterMod;

                        beginDate = referenceDate.AddDays(1);
                        endDate   = DurationParsingUtil.ShiftDateTime(durationResult.Timex, beginDate, true);

                        // Change the duration value and the beginDate
                        var unit = durationResult.Timex.Substring(durationResult.Timex.Length - 1);

                        durationResult.Timex = "P1" + unit;
                        beginDate            = DurationParsingUtil.ShiftDateTime(durationResult.Timex, endDate, false);
                    }

                    if (!string.IsNullOrEmpty(mod))
                    {
                        ((DateTimeResolutionResult)pr.Value).Mod = mod;
                    }

                    timex = durationResult.Timex;

                    ret.SubDateTimeEntities = new List <object> {
                        pr
                    };
                }
            }

            // Parse "rest of"
            var match = this.config.RestOfDateRegex.Match(text);

            if (match.Success)
            {
                var durationStr  = match.Groups["duration"].Value;
                var durationUnit = this.config.UnitMap[durationStr];
                switch (durationUnit)
                {
                case "W":
                    var diff = 7 - (((int)beginDate.DayOfWeek) == 0? 7: (int)beginDate.DayOfWeek);
                    endDate = beginDate.AddDays(diff);
                    timex   = "P" + diff + "D";
                    if (diff == 0)
                    {
                        restNowSunday = true;
                    }
                    break;

                case "MON":
                    endDate = DateObject.MinValue.SafeCreateFromValue(beginDate.Year, beginDate.Month, 1);
                    endDate = endDate.AddMonths(1).AddDays(-1);
                    diff    = endDate.Day - beginDate.Day + 1;
                    timex   = "P" + diff + "D";
                    break;

                case "Y":
                    endDate = DateObject.MinValue.SafeCreateFromValue(beginDate.Year, 12, 1);
                    endDate = endDate.AddMonths(1).AddDays(-1);
                    diff    = endDate.DayOfYear - beginDate.DayOfYear + 1;
                    timex   = "P" + diff + "D";
                    break;
                }
            }

            if (!beginDate.Equals(endDate) || restNowSunday)
            {
                endDate = InclusiveEndPeriod ? endDate.AddDays(-1) : endDate;

                ret.Timex =
                    $"({FormatUtil.LuisDate(beginDate)},{FormatUtil.LuisDate(endDate)},{timex})";
                ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate);
                ret.Success     = true;

                return(ret);
            }

            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);
        }
Example #4
0
        // Parse combined patterns Duration + Date, e.g. '3 days before Monday', '4 weeks after January 15th'
        private DateTimeResolutionResult ParseDurationWithDate(string text, DateObject referenceDate)
        {
            var ret         = new DateTimeResolutionResult();
            var durationRes = config.DurationExtractor.Extract(text, referenceDate);

            foreach (var duration in durationRes)
            {
                var matches = config.UnitRegex.Matches(duration.Text);
                if (matches.Count > 0)
                {
                    var afterStr = text.Substring((int)duration.Start + (int)duration.Length);

                    // Check if the Duration entity is followed by "before|from|after"
                    var connector = config.BeforeAfterRegex.MatchBegin(afterStr, trim: true);
                    if (connector.Success)
                    {
                        // Parse Duration
                        var pr = config.DurationParser.Parse(duration, referenceDate);

                        // Parse Date
                        if (pr.Value != null)
                        {
                            var dateString  = afterStr.Substring(connector.Index + connector.Length).Trim();
                            var innerResult = ParseBasicRegexMatch(dateString, referenceDate);
                            if (!innerResult.Success)
                            {
                                innerResult = ParseImplicitDate(dateString, referenceDate);
                            }

                            if (!innerResult.Success)
                            {
                                innerResult = ParseWeekdayOfMonth(dateString, referenceDate);
                            }

                            if (!innerResult.Success)
                            {
                                innerResult = ParseNumberWithMonth(dateString, referenceDate);
                            }

                            if (!innerResult.Success)
                            {
                                innerResult = ParseSingleNumber(dateString, referenceDate);
                            }

                            if (!innerResult.Success)
                            {
                                var holidayEr = new ExtractResult
                                {
                                    Start    = 0,
                                    Length   = dateString.Length,
                                    Text     = dateString,
                                    Type     = Constants.SYS_DATETIME_DATE,
                                    Data     = null,
                                    Metadata = new Metadata {
                                        IsHoliday = true
                                    },
                                };
                                innerResult = (DateTimeResolutionResult)config.HolidayParser.Parse(holidayEr, referenceDate).Value;
                            }

                            // Combine parsed results Duration + Date
                            if (innerResult.Success)
                            {
                                var        isFuture       = connector.Groups["after"].Success ? true : false;
                                DateObject date           = (DateObject)innerResult.FutureValue;
                                var        resultDateTime = DurationParsingUtil.ShiftDateTime(pr.TimexStr, date, future: isFuture);
                                ret.Timex = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}";

                                ret.FutureValue         = ret.PastValue = resultDateTime;
                                ret.SubDateTimeEntities = new List <object> {
                                    pr
                                };
                                ret.Success = true;
                            }
                        }
                    }
                }
            }

            return(ret);
        }
Example #5
0
        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);
        }
Example #6
0
        // Handle cases like "三天前" "Three days ago"
        private DateTimeResolutionResult ParserDurationWithAgoAndLater(string text, DateObject referenceDate)
        {
            var ret     = new DateTimeResolutionResult();
            var numStr  = string.Empty;
            var unitStr = string.Empty;

            var durationRes = this.config.DurationExtractor.Extract(text, referenceDate);

            if (durationRes.Count > 0)
            {
                var match = this.config.UnitRegex.Match(text);
                if (match.Success)
                {
                    var suffix  = text.Substring((int)durationRes[0].Start + (int)durationRes[0].Length).Trim();
                    var srcUnit = match.Groups["unit"].Value;

                    var numberStr = text.Substring((int)durationRes[0].Start, match.Index - (int)durationRes[0].Start).Trim();

                    var unitMatch = this.config.DurationRelativeDurationUnitRegex.Match(text);

                    // set the inexact number "数" (few) to 3 for now
                    var number = numberStr.Equals(unitMatch.Groups["few"].Value, StringComparison.Ordinal) ? 3 : ConvertCJKToNum(numberStr);

                    if (!numberStr.Equals(unitMatch.Groups["few"].Value, StringComparison.Ordinal))
                    {
                        if (suffix.Equals(unitMatch.Value, StringComparison.Ordinal))
                        {
                            var pr     = this.config.DurationParser.Parse(durationRes[0], referenceDate);
                            var future = suffix.Equals(unitMatch.Groups["later"].Value, StringComparison.Ordinal);
                            int swift  = 0;

                            if (pr != null)
                            {
                                var resultDateTime = DurationParsingUtil.ShiftDateTime(pr.TimexStr, referenceDate.AddDays(swift), future);
                                ret.Timex       = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}";
                                ret.FutureValue = ret.PastValue = resultDateTime;
                                ret.Success     = true;
                                return(ret);
                            }
                        }
                    }

                    if (this.config.UnitMap.ContainsKey(srcUnit))
                    {
                        unitStr   = this.config.UnitMap[srcUnit];
                        ret.Timex = TimexUtility.GenerateDurationTimex(number, unitStr, DurationParsingUtil.IsLessThanDay(unitStr));
                        DateObject date = Constants.InvalidDate;

                        var beforeMatch = this.config.BeforeRegex.Match(suffix);
                        if (beforeMatch.Success && suffix.StartsWith(beforeMatch.Value, StringComparison.Ordinal))
                        {
                            date = DurationParsingUtil.ShiftDateTime(ret.Timex, referenceDate, future: false);
                        }

                        var afterMatch = this.config.AfterRegex.Match(suffix);
                        if (afterMatch.Success && suffix.StartsWith(afterMatch.Value, StringComparison.Ordinal))
                        {
                            date = DurationParsingUtil.ShiftDateTime(ret.Timex, referenceDate, future: true);
                        }

                        if (date != Constants.InvalidDate)
                        {
                            ret.Timex       = $"{DateTimeFormatUtil.LuisDate(date)}";
                            ret.FutureValue = ret.PastValue = date;
                            ret.Success     = true;
                            return(ret);
                        }
                    }
                }
            }

            return(ret);
        }
Example #7
0
        // match several other cases
        // including '今天', '后天', '十三日'
        protected DateTimeResolutionResult ParseImplicitDate(string text, DateObject referenceDate)
        {
            var ret = new DateTimeResolutionResult();

            // handle "十二日" "明年这个月三日" "本月十一日"
            var match = this.config.SpecialDate.MatchExact(text, trim: true);

            if (match.Success)
            {
                var yearStr  = match.Groups["thisyear"].Value;
                var monthStr = match.Groups["thismonth"].Value;
                var dayStr   = match.Groups["day"].Value;

                int month = referenceDate.Month, year = referenceDate.Year;
                var day = this.config.DayOfMonth[dayStr];

                bool hasYear = false, hasMonth = false;

                if (!string.IsNullOrEmpty(monthStr))
                {
                    hasMonth = true;
                    if (this.config.NextRe.Match(monthStr).Success)
                    {
                        month++;
                        if (month == Constants.MaxMonth + 1)
                        {
                            month = Constants.MinMonth;
                            year++;
                        }
                    }
                    else if (this.config.LastRe.Match(monthStr).Success)
                    {
                        month--;
                        if (month == Constants.MinMonth - 1)
                        {
                            month = Constants.MaxMonth;
                            year--;
                        }
                    }

                    if (!string.IsNullOrEmpty(yearStr))
                    {
                        hasYear = true;
                        if (this.config.NextRe.Match(yearStr).Success)
                        {
                            ++year;
                        }
                        else if (this.config.LastRe.Match(yearStr).Success)
                        {
                            --year;
                        }
                    }
                }

                ret.Timex = DateTimeFormatUtil.LuisDate(hasYear ? year : -1, hasMonth ? month : -1, day);

                DateObject futureDate, pastDate;

                if (day > DateObjectExtension.GetMonthMaxDay(year, month))
                {
                    var futureMonth = month + 1;
                    var pastMonth   = month - 1;
                    var futureYear  = year;
                    var pastYear    = year;

                    if (futureMonth == Constants.MaxMonth + 1)
                    {
                        futureMonth = Constants.MinMonth;
                        futureYear  = year++;
                    }

                    if (pastMonth == Constants.MinMonth - 1)
                    {
                        pastMonth = Constants.MaxMonth;
                        pastYear  = year--;
                    }

                    var isFutureValid = DateObjectExtension.IsValidDate(futureYear, futureMonth, day);
                    var isPastValid   = DateObjectExtension.IsValidDate(pastYear, pastMonth, day);

                    if (isFutureValid && isPastValid)
                    {
                        futureDate = DateObject.MinValue.SafeCreateFromValue(futureYear, futureMonth, day);
                        pastDate   = DateObject.MinValue.SafeCreateFromValue(pastYear, pastMonth, day);
                    }
                    else if (isFutureValid && !isPastValid)
                    {
                        futureDate = pastDate = DateObject.MinValue.SafeCreateFromValue(futureYear, futureMonth, day);
                    }
                    else if (!isFutureValid && !isPastValid)
                    {
                        futureDate = pastDate = DateObject.MinValue.SafeCreateFromValue(pastYear, pastMonth, day);
                    }
                    else
                    {
                        // Fall back to normal cases, might lead to resolution failure
                        // TODO: Ideally, this failure should be filtered out in extract phase
                        futureDate = pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
                    }
                }
                else
                {
                    futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
                    pastDate   = DateObject.MinValue.SafeCreateFromValue(year, month, day);

                    if (!hasMonth)
                    {
                        if (futureDate < referenceDate)
                        {
                            if (IsValidDate(year, month + 1, day))
                            {
                                futureDate = futureDate.AddMonths(1);
                            }
                        }

                        if (pastDate >= referenceDate)
                        {
                            if (IsValidDate(year, month - 1, day))
                            {
                                pastDate = pastDate.AddMonths(-1);
                            }
                            else if (DateContext.IsFeb29th(year, month - 1, day))
                            {
                                pastDate = pastDate.AddMonths(-2);
                            }
                        }
                    }
                    else if (!hasYear)
                    {
                        if (futureDate < referenceDate)
                        {
                            if (IsValidDate(year + 1, month, day))
                            {
                                futureDate = futureDate.AddYears(1);
                            }
                        }

                        if (pastDate >= referenceDate)
                        {
                            if (IsValidDate(year - 1, month, day))
                            {
                                pastDate = pastDate.AddYears(-1);
                            }
                        }
                    }
                }

                ret.FutureValue = futureDate;
                ret.PastValue   = pastDate;
                ret.Success     = true;

                return(ret);
            }

            // handle cases like "昨日", "明日", "大后天"
            match = this.config.SpecialDayRegex.MatchExact(text, trim: true);

            if (match.Success)
            {
                var value = referenceDate.AddDays(this.config.GetSwiftDay(match.Value));
                ret.Timex       = DateTimeFormatUtil.LuisDate(value);
                ret.FutureValue = ret.PastValue = DateObject.MinValue.SafeCreateFromValue(value.Year, value.Month, value.Day);
                ret.Success     = true;

                return(ret);
            }

            // Handle "今から2日曜日" (2 Sundays from now)
            var exactMatch = this.config.SpecialDayWithNumRegex.MatchExact(text, trim: true);

            if (exactMatch.Success)
            {
                var numErs     = this.config.IntegerExtractor.Extract(text);
                var weekdayStr = exactMatch.Groups["weekday"].Value;

                if (!string.IsNullOrEmpty(weekdayStr) && numErs.Count > 0)
                {
                    var num   = Convert.ToInt32((double)(this.config.NumberParser.Parse(numErs[0]).Value ?? 0));
                    var value = referenceDate;

                    // Check whether the determined day of this week has passed.
                    if (value.DayOfWeek > (DayOfWeek)this.config.DayOfWeek[weekdayStr])
                    {
                        num--;
                    }

                    while (num-- > 0)
                    {
                        value = value.Next((DayOfWeek)this.config.DayOfWeek[weekdayStr]);
                    }

                    ret.Timex       = DateTimeFormatUtil.LuisDate(value);
                    ret.FutureValue = ret.PastValue = DateObject.MinValue.SafeCreateFromValue(value.Year, value.Month, value.Day);
                    ret.Success     = true;

                    return(ret);
                }
            }

            // handle "明日から3週間" (3 weeks from tomorrow)
            var durationResult = this.config.DurationExtractor.Extract(text, referenceDate);
            var unitMatch      = this.config.DurationRelativeDurationUnitRegex.Match(text);
            var isWithin       = this.config.DurationRelativeDurationUnitRegex.MatchEnd(text, trim: true).Groups[Constants.WithinGroupName].Success;

            if ((exactMatch.Success || isWithin) && unitMatch.Success && (durationResult.Count > 0) &&
                string.IsNullOrEmpty(unitMatch.Groups["few"].Value))
            {
                var pr     = this.config.DurationParser.Parse(durationResult[0], referenceDate);
                var dayStr = unitMatch.Groups["later"].Value;
                var future = true;
                int swift  = 0;

                if (pr != null)
                {
                    if (!string.IsNullOrEmpty(dayStr))
                    {
                        swift = this.config.GetSwiftDay(dayStr);
                    }

                    var resultDateTime = DurationParsingUtil.ShiftDateTime(pr.TimexStr, referenceDate.AddDays(swift), future);
                    ret.Timex       = $"{DateTimeFormatUtil.LuisDate(resultDateTime)}";
                    ret.FutureValue = ret.PastValue = resultDateTime;
                    ret.Success     = true;
                    return(ret);
                }
            }

            if (!ret.Success)
            {
                ret = MatchWeekdayAndDay(text, referenceDate);
            }

            if (!ret.Success)
            {
                ret = MatchThisWeekday(text, referenceDate);
            }

            if (!ret.Success)
            {
                ret = MatchNextWeekday(text, referenceDate);
            }

            if (!ret.Success)
            {
                ret = MatchLastWeekday(text, referenceDate);
            }

            if (!ret.Success)
            {
                ret = MatchWeekdayAlone(text, referenceDate);
            }

            return(ret);
        }
        // handle cases like "5分钟前", "1小时以后"
        private DateTimeResolutionResult ParserDurationWithAgoAndLater(string text, DateObject referenceDate)
        {
            var ret         = new DateTimeResolutionResult();
            var durationRes = this.config.DurationExtractor.Extract(text, referenceDate);

            if (durationRes.Count > 0)
            {
                var matchAgoLater = this.config.AgoLaterRegex.Match(text);

                if (matchAgoLater.Success)
                {
                    var pr       = config.DurationParser.Parse(durationRes[0], referenceDate);
                    var isFuture = matchAgoLater.Groups[Constants.LaterGroupName].Success;
                    var timex    = pr.TimexStr;

                    var resultDateTime = DurationParsingUtil.ShiftDateTime(timex, referenceDate, future: isFuture);
                    ret.Timex               = $"{DateTimeFormatUtil.LuisDateTime(resultDateTime)}";
                    ret.FutureValue         = ret.PastValue = resultDateTime;
                    ret.SubDateTimeEntities = new List <object> {
                        pr
                    };

                    ret.Success = true;
                    return(ret);
                }

                var match = this.config.DateTimePeriodUnitRegex.Match(text);
                if (match.Success)
                {
                    var suffix  = text.Substring((int)durationRes[0].Start + (int)durationRes[0].Length).Trim();
                    var srcUnit = match.Groups[Constants.UnitGroupName].Value;

                    var numberStr = text.Substring((int)durationRes[0].Start, match.Index - (int)durationRes[0].Start).Trim();
                    var number    = ConvertCJKToNum(numberStr);

                    if (this.config.UnitMap.ContainsKey(srcUnit))
                    {
                        var unitStr = this.config.UnitMap[srcUnit];

                        var beforeMatch = this.config.BeforeRegex.Match(suffix);
                        if (beforeMatch.Success && suffix.StartsWith(beforeMatch.Value, StringComparison.InvariantCulture))
                        {
                            DateObject date;
                            switch (unitStr)
                            {
                            case Constants.TimexHour:
                                date = referenceDate.AddHours(-number);
                                break;

                            case Constants.TimexMinute:
                                date = referenceDate.AddMinutes(-number);
                                break;

                            case Constants.TimexSecond:
                                date = referenceDate.AddSeconds(-number);
                                break;

                            default:
                                return(ret);
                            }

                            ret.Timex       = $"{DateTimeFormatUtil.LuisDate(date)}";
                            ret.FutureValue = ret.PastValue = date;
                            ret.Success     = true;
                            return(ret);
                        }

                        var afterMatch = this.config.AfterRegex.Match(suffix);
                        if (afterMatch.Success && suffix.StartsWith(afterMatch.Value, StringComparison.Ordinal))
                        {
                            DateObject date;
                            switch (unitStr)
                            {
                            case Constants.TimexHour:
                                date = referenceDate.AddHours(number);
                                break;

                            case Constants.TimexMinute:
                                date = referenceDate.AddMinutes(number);
                                break;

                            case Constants.TimexSecond:
                                date = referenceDate.AddSeconds(number);
                                break;

                            default:
                                return(ret);
                            }

                            ret.Timex       = $"{DateTimeFormatUtil.LuisDate(date)}";
                            ret.FutureValue = ret.PastValue = date;
                            ret.Success     = true;
                            return(ret);
                        }
                    }
                }
            }

            return(ret);
        }
Example #9
0
        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);
        }