// Parse "last minute", "next hour"
        private DateTimeResolutionResult ParseRelativeUnit(string text, DateObject referenceTime)
        {
            var ret = new DateTimeResolutionResult();

            var match = Config.RelativeTimeUnitRegex.Match(text);

            if (!match.Success)
            {
                match = this.Config.RestOfDateTimeRegex.Match(text);
            }

            if (match.Success)
            {
                var srcUnit = match.Groups["unit"].Value.ToLower();

                var unitStr = Config.UnitMap[srcUnit];

                int swiftValue  = 1;
                var prefixMatch = Config.PastRegex.Match(text);
                if (prefixMatch.Success)
                {
                    swiftValue = -1;
                }

                DateObject beginTime;
                var        endTime = beginTime = referenceTime;
                var        ptTimex = string.Empty;

                if (Config.UnitMap.ContainsKey(srcUnit))
                {
                    switch (unitStr)
                    {
                    case "D":
                        endTime = DateObject.MinValue.SafeCreateFromValue(beginTime.Year, beginTime.Month, beginTime.Day);
                        endTime = endTime.AddDays(1).AddSeconds(-1);
                        ptTimex = "PT" + (endTime - beginTime).TotalSeconds + "S";
                        break;

                    case "H":
                        beginTime = swiftValue > 0 ? beginTime : referenceTime.AddHours(swiftValue);
                        endTime   = swiftValue > 0 ? referenceTime.AddHours(swiftValue) : endTime;
                        ptTimex   = "PT1H";
                        break;

                    case "M":
                        beginTime = swiftValue > 0 ? beginTime : referenceTime.AddMinutes(swiftValue);
                        endTime   = swiftValue > 0 ? referenceTime.AddMinutes(swiftValue) : endTime;
                        ptTimex   = "PT1M";
                        break;

                    case "S":
                        beginTime = swiftValue > 0 ? beginTime : referenceTime.AddSeconds(swiftValue);
                        endTime   = swiftValue > 0 ? referenceTime.AddSeconds(swiftValue) : endTime;
                        ptTimex   = "PT1S";
                        break;

                    default:
                        return(ret);
                    }

                    ret.Timex =
                        $"({DateTimeFormatUtil.LuisDate(beginTime)}T{DateTimeFormatUtil.LuisTime(beginTime)}," +
                        $"{DateTimeFormatUtil.LuisDate(endTime)}T{DateTimeFormatUtil.LuisTime(endTime)},{ptTimex})";

                    ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginTime, endTime);
                    ret.Success     = true;

                    return(ret);
                }
            }

            return(ret);
        }
        // TODO: this can be abstracted with the similar method in BaseDatePeriodParser
        // Parse "in 20 minutes"
        private DateTimeResolutionResult ParseDuration(string text, DateObject referenceTime)
        {
            var ret = new DateTimeResolutionResult();

            // For the rest of datetime, it will be handled in next function
            if (Config.RestOfDateTimeRegex.IsMatch(text))
            {
                return(ret);
            }

            var ers = Config.DurationExtractor.Extract(text, referenceTime);

            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 numbersInSuffix   = Config.CardinalExtractor.Extract(beforeStr);
                var numbersInDuration = Config.CardinalExtractor.Extract(ers[0].Text);

                // Handle cases like "2 upcoming days", "5 previous years"
                if (numbersInSuffix.Any() && !numbersInDuration.Any())
                {
                    var numberEr           = numbersInSuffix.First();
                    var numberText         = numberEr.Text;
                    var durationText       = ers[0].Text;
                    var combinedText       = $"{numberText} {durationText}";
                    var combinedDurationEr = Config.DurationExtractor.Extract(combinedText, referenceTime);

                    if (combinedDurationEr.Any())
                    {
                        pr = Config.DurationParser.Parse(combinedDurationEr.First());
                        var startIndex = numberEr.Start.Value + numberEr.Length.Value;
                        beforeStr = beforeStr.Substring(startIndex).Trim();
                    }
                }

                if (pr.Value != null)
                {
                    var swiftSeconds   = 0;
                    var mod            = "";
                    var durationResult = (DateTimeResolutionResult)pr.Value;
                    if (durationResult.PastValue is double && durationResult.FutureValue is double)
                    {
                        swiftSeconds = (int)((double)durationResult.FutureValue);
                    }

                    DateObject beginTime;
                    var        endTime = beginTime = referenceTime;

                    if (Config.PastRegex.IsExactMatch(beforeStr, trim: true))
                    {
                        mod       = Constants.BEFORE_MOD;
                        beginTime = referenceTime.AddSeconds(-swiftSeconds);
                    }

                    // Handle the "within (the) (next) xx seconds/minutes/hours" case
                    // Should also handle the multiple duration case like P1DT8H
                    // Set the beginTime equal to reference time for now
                    if (Config.WithinNextPrefixRegex.IsExactMatch(beforeStr, trim: true))
                    {
                        endTime = beginTime.AddSeconds(swiftSeconds);
                    }

                    if (Config.FutureRegex.IsExactMatch(beforeStr, trim: true))
                    {
                        mod     = Constants.AFTER_MOD;
                        endTime = beginTime.AddSeconds(swiftSeconds);
                    }

                    if (Config.PastRegex.IsExactMatch(afterStr, trim: true))
                    {
                        mod       = Constants.BEFORE_MOD;
                        beginTime = referenceTime.AddSeconds(-swiftSeconds);
                    }

                    if (Config.FutureRegex.IsExactMatch(afterStr, trim: true))
                    {
                        mod     = Constants.AFTER_MOD;
                        endTime = beginTime.AddSeconds(swiftSeconds);
                    }

                    if (Config.FutureSuffixRegex.IsExactMatch(afterStr, trim: true))
                    {
                        mod     = Constants.AFTER_MOD;
                        endTime = beginTime.AddSeconds(swiftSeconds);
                    }

                    ret.Timex =
                        $"({DateTimeFormatUtil.LuisDate(beginTime)}T{DateTimeFormatUtil.LuisTime(beginTime)}," +
                        $"{DateTimeFormatUtil.LuisDate(endTime)}T{DateTimeFormatUtil.LuisTime(endTime)}," +
                        $"{durationResult.Timex})";

                    ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginTime, endTime);
                    ret.Success     = true;

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

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

                    return(ret);
                }
            }

            return(ret);
        }
Exemplo n.º 3
0
        // parse "in 20 minutes"
        private DateTimeResolutionResult ParseNumberWithUnit(string text, DateObject referenceTime)
        {
            var    ret = new DateTimeResolutionResult();
            string unitStr;

            // if there are spaces between number and unit
            var ers = this.config.CardinalExtractor.Extract(text);

            if (ers.Count == 1)
            {
                var pr      = this.config.CardinalParser.Parse(ers[0]);
                var srcUnit = text.Substring(ers[0].Start + ers[0].Length ?? 0).Trim();

                if (srcUnit.StartsWith("个", StringComparison.Ordinal))
                {
                    srcUnit = srcUnit.Substring(1);
                }

                var beforeStr = text.Substring(0, ers[0].Start ?? 0);
                if (this.config.UnitMap.ContainsKey(srcUnit))
                {
                    var numStr = pr.ResolutionStr;
                    unitStr = this.config.UnitMap[srcUnit];
                    var prefixMatch = this.config.PastRegex.MatchExact(beforeStr, trim: true);

                    if (prefixMatch.Success)
                    {
                        DateObject beginDate, endDate;
                        switch (unitStr)
                        {
                        case "H":
                            beginDate = referenceTime.AddHours(-(double)pr.Value);
                            endDate   = referenceTime;
                            break;

                        case "M":
                            beginDate = referenceTime.AddMinutes(-(double)pr.Value);
                            endDate   = referenceTime;
                            break;

                        case "S":
                            beginDate = referenceTime.AddSeconds(-(double)pr.Value);
                            endDate   = referenceTime;
                            break;

                        default:
                            return(ret);
                        }

                        ret.Timex =
                            $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT{numStr}{unitStr[0]})";
                        ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate);
                        ret.Success     = true;
                        return(ret);
                    }

                    prefixMatch = this.config.FutureRegex.MatchExact(beforeStr, trim: true);

                    if (!prefixMatch.Success)
                    {
                        prefixMatch = this.config.TimePeriodLeftRegex.MatchEnd(beforeStr, trim: true);
                    }

                    if (prefixMatch.Success)
                    {
                        DateObject beginDate, endDate;
                        switch (unitStr)
                        {
                        case "H":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddHours((double)pr.Value);
                            break;

                        case "M":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddMinutes((double)pr.Value);
                            break;

                        case "S":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddSeconds((double)pr.Value);
                            break;

                        default:
                            return(ret);
                        }

                        ret.Timex =
                            $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT{numStr}{unitStr[0]})";
                        ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate);
                        ret.Success     = true;
                        return(ret);
                    }
                }
            }

            // handle "last hour"
            var match = this.config.UnitRegex.Match(text);

            if (match.Success)
            {
                var srcUnit   = match.Groups[Constants.UnitGroupName].Value;
                var beforeStr = text.Substring(0, match.Index).Trim();
                if (this.config.UnitMap.ContainsKey(srcUnit))
                {
                    unitStr = this.config.UnitMap[srcUnit];

                    if (this.config.PastRegex.IsExactMatch(beforeStr, trim: true))
                    {
                        DateObject beginDate, endDate;
                        switch (unitStr)
                        {
                        case "H":
                            beginDate = referenceTime.AddHours(-1);
                            endDate   = referenceTime;
                            break;

                        case "M":
                            beginDate = referenceTime.AddMinutes(-1);
                            endDate   = referenceTime;
                            break;

                        case "S":
                            beginDate = referenceTime.AddSeconds(-1);
                            endDate   = referenceTime;
                            break;

                        default:
                            return(ret);
                        }

                        ret.Timex =
                            $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT1{unitStr[0]})";
                        ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate);
                        ret.Success     = true;
                        return(ret);
                    }

                    if (this.config.FutureRegex.IsExactMatch(beforeStr, trim: true))
                    {
                        DateObject beginDate, endDate;
                        switch (unitStr)
                        {
                        case "H":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddHours(1);
                            break;

                        case "M":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddMinutes(1);
                            break;

                        case "S":
                            beginDate = referenceTime;
                            endDate   = referenceTime.AddSeconds(1);
                            break;

                        default:
                            return(ret);
                        }

                        ret.Timex =
                            $"({DateTimeFormatUtil.LuisDate(beginDate)}T{DateTimeFormatUtil.LuisTime(beginDate)},{DateTimeFormatUtil.LuisDate(endDate)}T{DateTimeFormatUtil.LuisTime(endDate)},PT1{unitStr[0]})";
                        ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(beginDate, endDate);
                        ret.Success     = true;
                        return(ret);
                    }
                }
            }

            return(ret);
        }