コード例 #1
0
        // simple cases made by a number followed an unit
        private DateTimeResolutionResult ParseNumberWithUnit(string text, DateObject referenceTime)
        {
            DateTimeResolutionResult ret;

            if ((ret = ParseNumberSpaceUnit(text)).Success)
            {
                return(ret);
            }

            if ((ret = ParseNumberCombinedUnit(text)).Success)
            {
                return(ret);
            }

            if ((ret = ParseAnUnit(text)).Success)
            {
                return(ret);
            }

            if ((ret = DurationParsingUtil.ParseInexactNumberUnit(text, this.config)).Success)
            {
                return(ret);
            }

            return(ret);
        }
コード例 #2
0
        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);
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        public DateTimeParseResult Parse(ExtractResult er, DateObject refDate)
        {
            var referenceTime = refDate;

            var dateTimeParseResult = ParseMergedDuration(er.Text, referenceTime);

            if (!dateTimeParseResult.Success)
            {
                dateTimeParseResult = DurationParsingUtil.ParseInexactNumberUnit(er.Text, this.config);
            }

            if (!dateTimeParseResult.Success)
            {
                var parseResult = this.config.InternalParser.Parse(er);
                var unitResult  = parseResult.Value as UnitValue;

                if (unitResult == null)
                {
                    return(null);
                }

                var unitStr = unitResult.Unit;
                var number  = string.IsNullOrEmpty(unitResult.Number) ? 1 : double.Parse(unitResult.Number, CultureInfo.InvariantCulture);

                dateTimeParseResult.Timex       = TimexUtility.GenerateDurationTimex(number, unitStr, DurationParsingUtil.IsLessThanDay(unitStr));
                dateTimeParseResult.FutureValue = dateTimeParseResult.PastValue = number * this.config.UnitValueMap[unitStr];
                dateTimeParseResult.Success     = true;
            }

            if (dateTimeParseResult.Success)
            {
                dateTimeParseResult.FutureResolution = new Dictionary <string, string>
                {
                    { TimeTypeConstants.DURATION, dateTimeParseResult.FutureValue.ToString() },
                };

                dateTimeParseResult.PastResolution = new Dictionary <string, string>
                {
                    { TimeTypeConstants.DURATION, dateTimeParseResult.PastValue.ToString() },
                };
            }

            if (dateTimeParseResult.Success)
            {
                var moreOrLessMatch = config.MoreOrLessRegex.Match(er.Text);
                if (moreOrLessMatch.Success)
                {
                    if (moreOrLessMatch.Groups["less"].Success)
                    {
                        dateTimeParseResult.Mod = Constants.LESS_THAN_MOD;
                    }
                    else if (moreOrLessMatch.Groups["more"].Success)
                    {
                        dateTimeParseResult.Mod = Constants.MORE_THAN_MOD;
                    }
                }
            }

            var ret = new DateTimeParseResult
            {
                Text          = er.Text,
                Start         = er.Start,
                Length        = er.Length,
                Type          = er.Type,
                Data          = er.Data,
                Value         = dateTimeParseResult,
                TimexStr      = dateTimeParseResult.Timex,
                ResolutionStr = string.Empty,
            };

            return(ret);
        }
コード例 #5
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);
        }
コード例 #6
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);
        }
コード例 #7
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);
        }
コード例 #8
0
        // 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);
        }
コード例 #9
0
        private List <ExtractResult> MergeMultipleDuration(string text, List <ExtractResult> extractorResults)
        {
            if (extractorResults.Count <= 1)
            {
                return(extractorResults);
            }

            var unitMap      = this.config.UnitMap;
            var unitValueMap = this.config.UnitValueMap;
            var unitRegex    = this.config.DurationUnitRegex;
            List <ExtractResult>         results         = new List <ExtractResult>();
            List <List <ExtractResult> > separateResults = new List <List <ExtractResult> >();

            var firstExtractionIndex = 0;
            var timeUnit             = 0;
            var totalUnit            = 0;

            while (firstExtractionIndex < extractorResults.Count)
            {
                string curUnit   = null;
                var    unitMatch = unitRegex.Match(extractorResults[firstExtractionIndex].Text);

                if (unitMatch.Success && unitMap.ContainsKey(unitMatch.Groups["unit"].ToString()))
                {
                    curUnit = unitMatch.Groups["unit"].ToString();
                    totalUnit++;
                    if (DurationParsingUtil.IsTimeDurationUnit(unitMap[curUnit]))
                    {
                        timeUnit++;
                    }
                }

                if (string.IsNullOrEmpty(curUnit))
                {
                    firstExtractionIndex++;
                    continue;
                }

                // Add extraction to list of separate results (needed in case the extractions should not be merged)
                List <ExtractResult> separateList = new List <ExtractResult>()
                {
                    extractorResults[firstExtractionIndex]
                };

                var secondExtractionIndex = firstExtractionIndex + 1;
                while (secondExtractionIndex < extractorResults.Count)
                {
                    var valid       = false;
                    var midStrBegin = extractorResults[secondExtractionIndex - 1].Start + extractorResults[secondExtractionIndex - 1].Length ?? 0;
                    var midStrEnd   = extractorResults[secondExtractionIndex].Start ?? 0;
                    var midStr      = text.Substring(midStrBegin, midStrEnd - midStrBegin);
                    var match       = this.config.DurationConnectorRegex.Match(midStr);
                    if (match.Success)
                    {
                        unitMatch = unitRegex.Match(extractorResults[secondExtractionIndex].Text);
                        if (unitMatch.Success && unitMap.ContainsKey(unitMatch.Groups["unit"].ToString()))
                        {
                            var nextUnitStr = unitMatch.Groups["unit"].ToString();
                            if (unitValueMap[nextUnitStr] != unitValueMap[curUnit])
                            {
                                valid = true;
                                if (unitValueMap[nextUnitStr] < unitValueMap[curUnit])
                                {
                                    curUnit = nextUnitStr;
                                }
                            }

                            totalUnit++;
                            if (DurationParsingUtil.IsTimeDurationUnit(unitMap[nextUnitStr]))
                            {
                                timeUnit++;
                            }
                        }
                    }

                    if (!valid)
                    {
                        break;
                    }

                    // Add extraction to list of separate results (needed in case the extractions should not be merged)
                    separateList.Add(extractorResults[secondExtractionIndex]);

                    secondExtractionIndex++;
                }

                if (secondExtractionIndex - 1 > firstExtractionIndex)
                {
                    var node = new ExtractResult();
                    node.Start  = extractorResults[firstExtractionIndex].Start;
                    node.Length = extractorResults[secondExtractionIndex - 1].Start + extractorResults[secondExtractionIndex - 1].Length - node.Start;
                    node.Text   = text.Substring(node.Start ?? 0, node.Length ?? 0);
                    node.Type   = extractorResults[firstExtractionIndex].Type;

                    // Add multiple duration type to extract result
                    string type = Constants.MultipleDuration_DateTime; // Default type
                    if (timeUnit == totalUnit)
                    {
                        type = Constants.MultipleDuration_Time;
                    }
                    else if (timeUnit == 0)
                    {
                        type = Constants.MultipleDuration_Date;
                    }

                    node.Data = type;

                    results.Add(node);

                    timeUnit  = 0;
                    totalUnit = 0;
                }
                else
                {
                    results.Add(extractorResults[firstExtractionIndex]);
                }

                // Add list of separate extractions to separateResults, so that there is a 1 to 1 correspondence
                // between results (list of merged extractions) and separateResults (list of unmerged extractions)
                separateResults.Add(separateList);

                firstExtractionIndex = secondExtractionIndex;
            }

            // If the first and last elements of a group of contiguous extractions are both preceded/followed by modifiers,
            // they should not be merged, e.g. "last 2 weeks and 3 days ago"
            for (int i = results.Count - 1; i >= 0; i--)
            {
                var start     = (int)results[i].Start;
                var end       = start + (int)results[i].Length;
                var beforeStr = text.Substring(0, start);
                var afterStr  = text.Substring(end);
                var beforeMod = this.config.ModPrefixRegex.MatchEnd(beforeStr, trim: true);
                var afterMod  = this.config.ModSuffixRegex.MatchBegin(afterStr, trim: true);
                if (beforeMod.Success && afterMod.Success)
                {
                    results.RemoveAt(i);
                    results.InsertRange(i, separateResults[i]);
                }
            }

            return(results);
        }
コード例 #10
0
        private bool TryGetResultFromRegex(Regex regex, string text, string numStr, out DateTimeResolutionResult ret)
        {
            ret = new DateTimeResolutionResult();

            var match = regex.Match(text);

            if (match.Success)
            {
                var srcUnit = match.Groups["unit"].Value;
                if (this.config.UnitValueMap.ContainsKey(srcUnit))
                {
                    var unitStr = this.config.UnitMap[srcUnit];
                    var numVal  = double.Parse(numStr, CultureInfo.InvariantCulture);
                    ret.Timex       = TimexUtility.GenerateDurationTimex(numVal, unitStr, DurationParsingUtil.IsLessThanDay(unitStr));
                    ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit];
                    ret.Success     = true;
                }
            }

            return(match.Success);
        }
コード例 #11
0
        // handle cases that don't contain numbers
        private DateTimeResolutionResult ParseImplicitDuration(string text, DateObject referenceTime)
        {
            var ret = new DateTimeResolutionResult();

            // handle "all day" "all year"
            if (TryGetResultFromRegex(config.AllDateUnitRegex, text, "1", out var result))
            {
                ret = result;
            }

            // handle "half day", "half year"
            if (TryGetResultFromRegex(config.HalfDateUnitRegex, text, "0.5", out result))
            {
                ret = result;
            }

            // handle single duration unit, it is filtered in the extraction that there is a relative word in advance
            if (TryGetResultFromRegex(config.FollowedUnit, text, "1", out result))
            {
                ret = result;
            }

            // handle "during/for the day/week/month/year"
            if ((config.Options & DateTimeOptions.CalendarMode) != 0 &&
                TryGetResultFromRegex(config.DuringRegex, text, "1", out result))
            {
                ret = result;
            }
            else
            {
                // handle cases like "the hour", which are special durations always not in CalendarMode
                if ((this.config.Options & DateTimeOptions.CalendarMode) == 0)
                {
                    var regex = this.config.PrefixArticleRegex;

                    if (regex != null)
                    {
                        var match = RegExpUtility.MatchBegin(regex, text, false);
                        if (match.Success)
                        {
                            var srcUnit = text.Substring(match.Length);
                            if (this.config.UnitValueMap.ContainsKey(srcUnit))
                            {
                                var numStr  = "1";
                                var unitStr = this.config.UnitMap[srcUnit];
                                var numVal  = double.Parse(numStr, CultureInfo.InvariantCulture);

                                ret.Timex       = TimexUtility.GenerateDurationTimex(numVal, unitStr, DurationParsingUtil.IsLessThanDay(unitStr));
                                ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit];
                                ret.Success     = true;
                            }
                        }
                    }
                }
            }

            return(ret);
        }
コード例 #12
0
        private DateTimeResolutionResult ParseAnUnit(string text)
        {
            var ret       = new DateTimeResolutionResult();
            var suffixStr = text;

            var match = this.config.AnUnitRegex.Match(text);

            if (!match.Success)
            {
                match = this.config.HalfDateUnitRegex.Match(text);
            }

            if (match.Success)
            {
                var numVal = match.Groups["half"].Success ? 0.5 : 1;
                numVal = match.Groups["quarter"].Success ? 0.25 : numVal;
                numVal = match.Groups["threequarter"].Success ? 0.75 : numVal;

                numVal += ParseNumberWithUnitAndSuffix(suffixStr);

                var srcUnit = match.Groups["unit"].Value;
                if (this.config.UnitMap.ContainsKey(srcUnit))
                {
                    var unitStr = this.config.UnitMap[srcUnit];

                    ret.Timex       = TimexUtility.GenerateDurationTimex(numVal, unitStr, DurationParsingUtil.IsLessThanDay(unitStr));
                    ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit];
                    ret.Success     = true;
                }
                else if (match.Groups[Constants.BusinessDayGroupName].Success)
                {
                    ret.Timex = TimexUtility.GenerateDurationTimex(numVal, Constants.TimexBusinessDay, false);

                    // The line below was containing this.config.UnitValueMap[srcUnit.Split()[1]]
                    // it was updated to accommodate single word "business day" expressions.
                    ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit.Split()[srcUnit.Split().Length - 1]];
                    ret.Success     = true;
                }
            }

            return(ret);
        }
コード例 #13
0
        private DateTimeResolutionResult ParseNumberCombinedUnit(string text)
        {
            var ret       = new DateTimeResolutionResult();
            var suffixStr = text;

            // if there are NO spaces between number and unit
            var match = this.config.NumberCombinedWithUnit.Match(text);

            if (match.Success)
            {
                var numVal = double.Parse(match.Groups["num"].Value, CultureInfo.InvariantCulture) + ParseNumberWithUnitAndSuffix(suffixStr);

                var srcUnit = match.Groups["unit"].Value;
                if (this.config.UnitMap.ContainsKey(srcUnit))
                {
                    var unitStr = this.config.UnitMap[srcUnit];

                    if (numVal > 1000 && (unitStr.Equals(Constants.TimexYear, StringComparison.Ordinal) ||
                                          unitStr.Equals(Constants.TimexMonthFull, StringComparison.Ordinal) ||
                                          unitStr.Equals(Constants.TimexWeek, StringComparison.Ordinal)))
                    {
                        return(ret);
                    }

                    ret.Timex       = TimexUtility.GenerateDurationTimex(numVal, unitStr, DurationParsingUtil.IsLessThanDay(unitStr));
                    ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit];
                    ret.Success     = true;

                    return(ret);
                }
            }

            return(ret);
        }
コード例 #14
0
        private DateTimeResolutionResult ParseNumberSpaceUnit(string text)
        {
            var ret       = new DateTimeResolutionResult();
            var suffixStr = text;

            // if there are spaces between number and unit
            var ers = ExtractNumbersBeforeUnit(text);

            if (ers.Count == 1)
            {
                var pr = this.config.NumberParser.Parse(ers[0]);

                // followed unit: {num} (<followed unit>and a half hours)
                var srcUnit = string.Empty;
                var noNum   = text.Substring(ers[0].Start + ers[0].Length ?? 0).Trim();

                var match = this.config.FollowedUnit.Match(noNum);
                if (match.Success)
                {
                    srcUnit   = match.Groups["unit"].Value;
                    suffixStr = match.Groups[Constants.SuffixGroupName].Value;

                    // check also beforeStr for "and an half"
                    if (this.config.CheckBothBeforeAfter && string.IsNullOrEmpty(suffixStr))
                    {
                        noNum = text.Substring(0, (int)ers[0].Start).Trim();
                        var prefixMatch = this.config.SuffixAndRegex.Match(noNum);
                        if (prefixMatch.Success)
                        {
                            suffixStr = prefixMatch.Groups[Constants.SuffixGroupName].Value;
                        }
                    }
                }

                if (match.Success && match.Groups[Constants.BusinessDayGroupName].Success)
                {
                    var numVal = int.Parse(pr.Value.ToString(), CultureInfo.InvariantCulture);
                    ret.Timex = TimexUtility.GenerateDurationTimex(numVal, Constants.TimexBusinessDay, false);

                    // The line below was containing this.config.UnitValueMap[srcUnit.Split()[1]]
                    // it was updated to accommodate single word "business day" expressions.
                    ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit.Split()[srcUnit.Split().Length - 1]];
                    ret.Success     = true;

                    return(ret);
                }

                if (this.config.UnitMap.TryGetValue(srcUnit, out var unitStr))
                {
                    // First try to parse combined expression 'num + suffix'
                    double numVal;
                    var    combStr = pr.Text + " " + suffixStr;
                    if (this.config.DoubleNumbers.ContainsKey(combStr))
                    {
                        numVal = ParseNumberWithUnitAndSuffix(combStr);
                    }
                    else
                    {
                        numVal = double.Parse(pr.Value.ToString(), CultureInfo.InvariantCulture) + ParseNumberWithUnitAndSuffix(suffixStr);
                    }

                    ret.Timex       = TimexUtility.GenerateDurationTimex(numVal, unitStr, DurationParsingUtil.IsLessThanDay(unitStr));
                    ret.FutureValue = ret.PastValue = numVal * this.config.UnitValueMap[srcUnit];
                    ret.Success     = true;
                    return(ret);
                }
            }

            return(ret);
        }
コード例 #15
0
        private List <ExtractResult> MergeMultipleDuration(string text, List <ExtractResult> extractorResults)
        {
            if (extractorResults.Count <= 1)
            {
                return(extractorResults);
            }

            var unitMap              = this.config.UnitMap;
            var unitValueMap         = this.config.UnitValueMap;
            var unitRegex            = this.config.DurationUnitRegex;
            List <ExtractResult> ret = new List <ExtractResult>();

            var firstExtractionIndex = 0;
            var timeUnit             = 0;
            var totalUnit            = 0;

            while (firstExtractionIndex < extractorResults.Count)
            {
                string curUnit   = null;
                var    unitMatch = unitRegex.Match(extractorResults[firstExtractionIndex].Text);

                if (unitMatch.Success && unitMap.ContainsKey(unitMatch.Groups["unit"].ToString()))
                {
                    curUnit = unitMatch.Groups["unit"].ToString();
                    totalUnit++;
                    if (DurationParsingUtil.IsTimeDurationUnit(unitMap[curUnit]))
                    {
                        timeUnit++;
                    }
                }

                if (string.IsNullOrEmpty(curUnit))
                {
                    firstExtractionIndex++;
                    continue;
                }

                var secondExtractionIndex = firstExtractionIndex + 1;
                while (secondExtractionIndex < extractorResults.Count)
                {
                    var valid       = false;
                    var midStrBegin = extractorResults[secondExtractionIndex - 1].Start + extractorResults[secondExtractionIndex - 1].Length ?? 0;
                    var midStrEnd   = extractorResults[secondExtractionIndex].Start ?? 0;
                    if (midStrBegin > midStrEnd)
                    {
                        return(extractorResults);
                    }

                    var midStr = text.Substring(midStrBegin, midStrEnd - midStrBegin);
                    var match  = this.config.DurationConnectorRegex.Match(midStr);
                    if (match.Success)
                    {
                        unitMatch = unitRegex.Match(extractorResults[secondExtractionIndex].Text);
                        if (unitMatch.Success && unitMap.ContainsKey(unitMatch.Groups["unit"].ToString()))
                        {
                            var nextUnitStr = unitMatch.Groups["unit"].ToString();
                            if (unitValueMap[unitMap[nextUnitStr]] != unitValueMap[unitMap[curUnit]])
                            {
                                valid = true;
                                if (unitValueMap[unitMap[nextUnitStr]] < unitValueMap[unitMap[curUnit]])
                                {
                                    curUnit = nextUnitStr;
                                }
                            }

                            totalUnit++;
                            if (DurationParsingUtil.IsTimeDurationUnit(unitMap[nextUnitStr]))
                            {
                                timeUnit++;
                            }
                        }
                    }

                    if (!valid)
                    {
                        break;
                    }

                    secondExtractionIndex++;
                }

                if (secondExtractionIndex - 1 > firstExtractionIndex)
                {
                    var node = new ExtractResult();
                    node.Start  = extractorResults[firstExtractionIndex].Start;
                    node.Length = extractorResults[secondExtractionIndex - 1].Start + extractorResults[secondExtractionIndex - 1].Length - node.Start;
                    node.Text   = text.Substring(node.Start ?? 0, node.Length ?? 0);
                    node.Type   = extractorResults[firstExtractionIndex].Type;

                    // Add multiple duration type to extract result
                    string type = Constants.MultipleDuration_DateTime; // Default type
                    if (timeUnit == totalUnit)
                    {
                        type = Constants.MultipleDuration_Time;
                    }
                    else if (timeUnit == 0)
                    {
                        type = Constants.MultipleDuration_Date;
                    }

                    node.Data = type;

                    ret.Add(node);

                    timeUnit  = 0;
                    totalUnit = 0;
                }
                else
                {
                    ret.Add(extractorResults[firstExtractionIndex]);
                }

                firstExtractionIndex = secondExtractionIndex;
            }

            return(ret);
        }
コード例 #16
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);
        }
コード例 #17
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);
        }
コード例 #18
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);
        }