Esempio n. 1
0
        // parse a regex match which includes 'day', 'month' and 'year' (optional) group
        protected DateTimeResolutionResult Match2Date(Match match, DateObject referenceDate)
        {
            var ret = new DateTimeResolutionResult();

            var monthStr = match.Groups["month"].Value;
            var dayStr = match.Groups["day"].Value;
            var yearStr = match.Groups["year"].Value;
            var yearCJKStr = match.Groups[Constants.YearCJKGroupName].Value;
            int month = 0, day = 0, year = 0;

            var tmp = ConvertCJKYearToInteger(yearCJKStr);

            year = tmp == -1 ? 0 : tmp;

            if (this.config.MonthOfYear.ContainsKey(monthStr) && this.config.DayOfMonth.ContainsKey(dayStr))
            {
                month = this.config.MonthOfYear[monthStr] > 12 ? this.config.MonthOfYear[monthStr] % 12 : this.config.MonthOfYear[monthStr];
                day   = this.config.DayOfMonth[dayStr] > 31 ? this.config.DayOfMonth[dayStr] % 31 : this.config.DayOfMonth[dayStr];
                if (!string.IsNullOrEmpty(yearStr))
                {
                    year = int.Parse(yearStr, CultureInfo.InvariantCulture);
                    if (year < 100 && year >= Constants.MinTwoDigitYearPastNum)
                    {
                        year += Constants.BASE_YEAR_PAST_CENTURY;
                    }
                    else if (year >= 0 && year < Constants.MaxTwoDigitYearFutureNum)
                    {
                        year += Constants.BASE_YEAR_CURRENT_CENTURY;
                    }
                }
            }

            var noYear = false;

            if (year == 0)
            {
                year      = referenceDate.Year;
                ret.Timex = DateTimeFormatUtil.LuisDate(-1, month, day);
                noYear    = true;
            }
            else
            {
                ret.Timex = DateTimeFormatUtil.LuisDate(year, month, day);
            }

            var futurePastDates = DateContext.GenerateDates(noYear, referenceDate, year, month, day);

            ret.FutureValue = futurePastDates.future;
            ret.PastValue   = futurePastDates.past;
            ret.Success     = true;

            return(ret);
        }
Esempio n. 2
0
 public static string SetTimexWithContext(string timex, DateContext context)
 {
     return(timex.Replace(Constants.TimexFuzzyYear, context.Year.ToString("D4")));
 }
Esempio n. 3
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 > 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);
            }

            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);
        }
Esempio n. 4
0
        // Parse a regex match which includes 'day', 'month' and 'year' (optional) group
        private DateTimeResolutionResult Match2Date(Match match, DateObject referenceDate, string relativeStr)
        {
            var ret = new DateTimeResolutionResult();
            int month = 0, day = 0, year = 0;

            var monthStr         = match.Groups["month"].Value;
            var dayStr           = match.Groups["day"].Value;
            var weekdayStr       = match.Groups["weekday"].Value;
            var yearStr          = match.Groups["year"].Value;
            var writtenYear      = match.Groups["fullyear"].Value;
            var ambiguousCentury = false;

            if (this.config.MonthOfYear.ContainsKey(monthStr) && this.config.DayOfMonth.ContainsKey(dayStr))
            {
                month = this.config.MonthOfYear[monthStr];
                day   = this.config.DayOfMonth[dayStr];

                if (!string.IsNullOrEmpty(writtenYear))
                {
                    year = this.config.DateExtractor.GetYearFromText(match);
                }
                else if (!string.IsNullOrEmpty(yearStr))
                {
                    year = int.Parse(yearStr, CultureInfo.InvariantCulture);
                    if (year < 100 && year >= Constants.MinTwoDigitYearPastNum)
                    {
                        year += Constants.BASE_YEAR_PAST_CENTURY;
                    }
                    else if (year >= 0 && year < Constants.MaxTwoDigitYearFutureNum)
                    {
                        year += Constants.BASE_YEAR_CURRENT_CENTURY;
                    }
                    else if (year >= Constants.MaxTwoDigitYearFutureNum && year < Constants.MinTwoDigitYearPastNum)
                    {
                        // Two-digit years in the range [30, 40) are ambiguos
                        ambiguousCentury = true;
                    }
                }
            }

            var noYear = false;

            if (year == 0)
            {
                year = referenceDate.Year;
                if (!string.IsNullOrEmpty(relativeStr))
                {
                    var swift = this.config.GetSwiftMonthOrYear(relativeStr);

                    // @TODO Improve handling of next/last in particular cases "next friday 5/12" when the next friday is not 5/12.
                    if (!string.IsNullOrEmpty(weekdayStr))
                    {
                        swift = 0;
                    }

                    year += swift;
                }
                else
                {
                    noYear = true;
                }

                ret.Timex = DateTimeFormatUtil.LuisDate(-1, month, day);
            }
            else
            {
                ret.Timex = DateTimeFormatUtil.LuisDate(year, month, day);
            }

            var futurePastDates = DateContext.GenerateDates(noYear, referenceDate, year, month, day);

            ret.FutureValue = futurePastDates.future;
            ret.PastValue   = futurePastDates.past;
            ret.Success     = true;

            // Ambiguous two-digit years are assigned values in both centuries (e.g. 35 -> 1935, 2035)
            if (ambiguousCentury)
            {
                ret.PastValue   = futurePastDates.past.AddYears(Constants.BASE_YEAR_PAST_CENTURY);
                ret.FutureValue = futurePastDates.future.AddYears(Constants.BASE_YEAR_CURRENT_CENTURY);
                ret.Timex       = TimexUtility.ModifyAmbiguousCenturyTimex(ret.Timex);
            }

            return(ret);
        }
Esempio n. 5
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);
        }
Esempio n. 6
0
        // Parse a regex match which includes 'day', 'month' and 'year' (optional) group
        private DateTimeResolutionResult Match2Date(Match match, DateObject referenceDate, string relativeStr)
        {
            var ret = new DateTimeResolutionResult();
            int month = 0, day = 0, year = 0;

            var monthStr    = match.Groups["month"].Value;
            var dayStr      = match.Groups["day"].Value;
            var weekdayStr  = match.Groups["weekday"].Value;
            var yearStr     = match.Groups["year"].Value;
            var writtenYear = match.Groups["fullyear"].Value;

            if (this.config.MonthOfYear.ContainsKey(monthStr) && this.config.DayOfMonth.ContainsKey(dayStr))
            {
                month = this.config.MonthOfYear[monthStr];
                day   = this.config.DayOfMonth[dayStr];

                if (!string.IsNullOrEmpty(writtenYear))
                {
                    year = this.config.DateExtractor.GetYearFromText(match);
                }
                else if (!string.IsNullOrEmpty(yearStr))
                {
                    year = int.Parse(yearStr, CultureInfo.InvariantCulture);
                    if (year < 100 && year >= Constants.MinTwoDigitYearPastNum)
                    {
                        year += 1900;
                    }
                    else if (year >= 0 && year < Constants.MaxTwoDigitYearFutureNum)
                    {
                        year += 2000;
                    }
                }
            }

            var noYear = false;

            if (year == 0)
            {
                year = referenceDate.Year;
                if (!string.IsNullOrEmpty(relativeStr))
                {
                    var swift = this.config.GetSwiftMonthOrYear(relativeStr);

                    // @TODO Improve handling of next/last in particular cases "next friday 5/12" when the next friday is not 5/12.
                    if (!string.IsNullOrEmpty(weekdayStr))
                    {
                        swift = 0;
                    }

                    year += swift;
                }
                else
                {
                    noYear = true;
                }

                ret.Timex = DateTimeFormatUtil.LuisDate(-1, month, day);
            }
            else
            {
                ret.Timex = DateTimeFormatUtil.LuisDate(year, month, day);
            }

            var futurePastDates = DateContext.GenerateDates(noYear, referenceDate, year, month, day);

            ret.FutureValue = futurePastDates.future;
            ret.PastValue   = futurePastDates.past;
            ret.Success     = true;

            return(ret);
        }