コード例 #1
0
        public new ParseResult Parse(ExtractResult er, DateObject refTime)
        {
            var referenceTime = refTime;
            DateTimeParseResult pr;

            // push, save teh MOD string
            bool hasBefore = false, hasAfter = false, hasSince = false;

            if (BeforeRegex.IsMatch(er.Text))
            {
                hasBefore = true;
            }
            else if (AfterRegex.IsMatch(er.Text))
            {
                hasAfter = true;
            }
            else if (SinceRegex.IsMatch(er.Text))
            {
                hasSince = true;
            }

            if (er.Type.Equals(Constants.SYS_DATETIME_DATE, StringComparison.Ordinal))
            {
                pr = this.Config.DateParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_TIME, StringComparison.Ordinal))
            {
                pr = this.Config.TimeParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIME, StringComparison.Ordinal))
            {
                pr = this.Config.DateTimeParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD, StringComparison.Ordinal))
            {
                pr = this.Config.DatePeriodParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_TIMEPERIOD, StringComparison.Ordinal))
            {
                pr = this.Config.TimePeriodParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIMEPERIOD, StringComparison.Ordinal))
            {
                pr = this.Config.DateTimePeriodParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_DURATION, StringComparison.Ordinal))
            {
                pr = this.Config.DurationParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_SET, StringComparison.Ordinal))
            {
                pr = this.Config.SetParser.Parse(er, referenceTime);
            }
            else
            {
                return(null);
            }

            // pop, restore the MOD string
            if (hasBefore)
            {
                var val = (DateTimeResolutionResult)pr.Value;
                if (val != null)
                {
                    val.Mod = Constants.BEFORE_MOD;
                }

                pr.Value = val;
            }

            if (hasAfter)
            {
                var val = (DateTimeResolutionResult)pr.Value;
                if (val != null)
                {
                    val.Mod = Constants.AFTER_MOD;
                }

                pr.Value = val;
            }

            if (hasSince)
            {
                var val = (DateTimeResolutionResult)pr.Value;
                if (val != null)
                {
                    val.Mod = Constants.SINCE_MOD;
                }

                pr.Value = val;
            }

            pr.Value = DateTimeResolution(pr);

            var hasModifier = hasBefore || hasAfter || hasSince;

            // change the type at last for the after or before mode
            pr.Type = $"{ParserTypeName}.{DetermineDateTimeType(er.Type, hasModifier)}";

            return(pr);
        }
コード例 #2
0
 private static bool IsMultipleDurationDate(ExtractResult er)
 {
     return(er.Data != null && er.Data.ToString() == Constants.MultipleDuration_Date);
 }
コード例 #3
0
 // Cases like "more than 3 days", "less than 4 weeks"
 private static bool IsInequalityDuration(ExtractResult er)
 {
     return(er.Data != null && (er.Data.ToString() == Constants.MORE_THAN_MOD || er.Data.ToString() == Constants.LESS_THAN_MOD));
 }
コード例 #4
0
        public List <ExtractResult> Extract(string source)
        {
            var result = new List <ExtractResult>();
            IOrderedEnumerable <ExtractResult> numbers;

            if (!PreCheckStr(source))
            {
                return(result);
            }

            var mappingPrefix = new Dictionary <int, PrefixUnitResult>();
            var sourceLen     = source.Length;
            var prefixMatched = false;
            var unitIsPrefix  = new List <bool>();

            MatchCollection nonUnitMatches = null;
            var             prefixMatches  = prefixMatcher.Find(source).OrderBy(o => o.Start).ToList();
            var             suffixMatches  = suffixMatcher.Find(source).OrderBy(o => o.Start).ToList();

            // Remove matches with wrong length, e.g. both 'm2' and 'm 2' are extracted but only 'm2' represents a unit.
            for (int i = suffixMatches.Count - 1; i >= 0; i--)
            {
                var m = suffixMatches[i];
                if (m.CanonicalValues.All(l => l.Length != m.Length))
                {
                    suffixMatches.RemoveAt(i);
                }
            }

            if (prefixMatches.Count > 0 || suffixMatches.Count > 0)
            {
                numbers = this.config.UnitNumExtractor.Extract(source).OrderBy(o => o.Start);

                // Checking if there are conflicting interpretations between currency unit as prefix and suffix for each number.
                // For example, in Chinese, "$20,300美圆" should be broken into two entities instead of treating 20,300 as one number: "$20" and "300美圆".
                if (numbers.Any() && CheckExtractorType(Constants.SYS_UNIT_CURRENCY) && prefixMatches.Any() && suffixMatches.Any())
                {
                    foreach (var number in numbers)
                    {
                        int start = (int)number.Start, length = (int)number.Length;
                        var numberPrefix = prefixMatches.Any(o => o.Start + o.Length == number.Start);
                        var numberSuffix = suffixMatches.Any(o => o.Start == number.Start + number.Length);

                        if (numberPrefix != false && numberSuffix != false && number.Text.Contains(","))
                        {
                            int commaIndex = (int)number.Start + number.Text.IndexOf(",");
                            source = source.Substring(0, commaIndex) + " " + source.Substring(commaIndex + 1);
                        }
                    }

                    numbers = this.config.UnitNumExtractor.Extract(source).OrderBy(o => o.Start);
                }

                // Special case for cases where number multipliers clash with unit
                var ambiguousMultiplierRegex = this.config.AmbiguousUnitNumberMultiplierRegex;
                if (ambiguousMultiplierRegex != null)
                {
                    foreach (var number in numbers)
                    {
                        var match = ambiguousMultiplierRegex.Matches(number.Text);
                        if (match.Count == 1)
                        {
                            var newLength = number.Text.Length - match[0].Length;
                            number.Text   = number.Text.Substring(0, newLength);
                            number.Length = newLength;
                        }
                    }
                }

                foreach (var number in numbers)
                {
                    if (number.Start == null || number.Length == null)
                    {
                        continue;
                    }

                    int start = (int)number.Start, length = (int)number.Length;
                    var maxFindPref = Math.Min(maxPrefixMatchLen, number.Start.Value);
                    var maxFindSuff = sourceLen - start - length;

                    var closeMatch = false;
                    if (maxFindPref != 0)
                    {
                        // Scan from left to right, find the longest match
                        var lastIndex = start;
                        MatchResult <string> bestMatch = null;

                        foreach (var m in prefixMatches)
                        {
                            if (m.Length > 0 && m.End > start)
                            {
                                break;
                            }

                            var unitStr = source.Substring(m.Start, lastIndex - m.Start);
                            if (m.Length > 0 && unitStr.Trim() == m.Text)
                            {
                                if (unitStr == m.Text)
                                {
                                    closeMatch = true;
                                }

                                bestMatch = m;
                                break;
                            }
                        }

                        if (bestMatch != null)
                        {
                            var offSet  = lastIndex - bestMatch.Start;
                            var unitStr = source.Substring(bestMatch.Start, offSet);
                            mappingPrefix[number.Start.Value] = new PrefixUnitResult {
                                Offset = offSet, UnitStr = unitStr
                            };
                        }
                    }

                    mappingPrefix.TryGetValue(start, out PrefixUnitResult prefixUnit);

                    // For currency unit, such as "$ 10 $ 20", get candidate "$ 10" "10 $" "$20" then select to get result.
                    // So add "$ 10" to result here, then get "10 $" in the suffixMatch.
                    // But for case like "摄氏温度10度", "摄氏温度10" will skip this and continue to extend the suffix.
                    if (prefixUnit != null && !prefixMatched && CheckExtractorType(Constants.SYS_UNIT_CURRENCY))
                    {
                        var er = new ExtractResult
                        {
                            Start  = number.Start - prefixUnit.Offset,
                            Length = number.Length + prefixUnit.Offset,
                            Text   = prefixUnit.UnitStr + number.Text,
                            Type   = this.config.ExtractType,
                        };

                        // Relative position will be used in Parser
                        var numberData = number.Clone();
                        numberData.Start = start - er.Start;
                        er.Data          = numberData;

                        result.Add(er);
                        unitIsPrefix.Add(true);
                    }

                    if (maxFindSuff > 0)
                    {
                        // If the number already get close prefix currency unit, skip the suffix match.
                        if (CheckExtractorType(Constants.SYS_UNIT_CURRENCY) && closeMatch)
                        {
                            continue;
                        }

                        // find the best suffix unit
                        var maxlen     = 0;
                        var firstIndex = start + length;

                        foreach (var m in suffixMatches)
                        {
                            if (m.Length > 0 && m.Start >= firstIndex)
                            {
                                var endpos = m.Start + m.Length - firstIndex;
                                if (maxlen < endpos)
                                {
                                    var midStr = source.Substring(firstIndex, m.Start - firstIndex);
                                    if (string.IsNullOrWhiteSpace(midStr) || midStr.Trim().Equals(this.config.ConnectorToken, StringComparison.Ordinal))
                                    {
                                        maxlen = endpos;
                                    }
                                }
                            }
                        }

                        if (maxlen != 0)
                        {
                            var substr = source.Substring(start, length + maxlen);

                            var er = new ExtractResult
                            {
                                Start  = start,
                                Length = length + maxlen,
                                Text   = substr,
                                Type   = this.config.ExtractType,
                            };

                            if (prefixUnit != null && !CheckExtractorType(Constants.SYS_UNIT_CURRENCY))
                            {
                                prefixMatched = true;
                                er.Start     -= prefixUnit.Offset;
                                er.Length    += prefixUnit.Offset;
                                er.Text       = prefixUnit.UnitStr + er.Text;
                            }

                            // Relative position will be used in Parser
                            var numberData = number.Clone();
                            numberData.Start = start - er.Start;
                            er.Data          = numberData;

                            // Special treatment, handle cases like '2:00 pm', '00 pm' is not dimension
                            var isNotUnit = false;
                            if (er.Type.Equals(Constants.SYS_UNIT_DIMENSION, StringComparison.Ordinal))
                            {
                                if (nonUnitMatches == null)
                                {
                                    nonUnitMatches = this.config.NonUnitRegex.Matches(source);
                                }

                                foreach (Match time in nonUnitMatches)
                                {
                                    if (er.Start >= time.Index && er.Start + er.Length <= time.Index + time.Length)
                                    {
                                        isNotUnit = true;
                                        break;
                                    }
                                }
                            }

                            if (isNotUnit)
                            {
                                continue;
                            }

                            result.Add(er);
                            unitIsPrefix.Add(false);
                        }
                    }

                    if (prefixUnit != null && !prefixMatched && !CheckExtractorType(Constants.SYS_UNIT_CURRENCY))
                    {
                        var er = new ExtractResult
                        {
                            Start  = number.Start - prefixUnit.Offset,
                            Length = number.Length + prefixUnit.Offset,
                            Text   = prefixUnit.UnitStr + number.Text,
                            Type   = this.config.ExtractType,
                        };

                        // Relative position will be used in Parser
                        var numberData = number.Clone();
                        numberData.Start = start - er.Start;
                        er.Data          = numberData;

                        result.Add(er);
                    }
                }
            }
            else
            {
                numbers = null;
            }

            // Extract Separate unit
            if (separateRegex != null)
            {
                if (nonUnitMatches == null)
                {
                    nonUnitMatches = this.config.NonUnitRegex.Matches(source);
                }

                ExtractSeparateUnits(source, result, nonUnitMatches);
            }

            // Remove common ambiguous cases
            result = FilterAmbiguity(result, source);

            if (CheckExtractorType(Constants.SYS_UNIT_CURRENCY))
            {
                result = SelectCandidates(source, result, unitIsPrefix);
            }

            // Expand Chinese phrase to the `half` patterns when it follows closely origin phrase.
            this.config.ExpandHalfSuffix(source, ref result, numbers);

            return(result);
        }
コード例 #5
0
 public ParseResult Parse(ExtractResult extResult)
 {
     return(Parse(extResult, DateObject.Now));
 }
コード例 #6
0
 public ParseResult Parse(ExtractResult result)
 {
     return(this.Parse(result, DateObject.Now));
 }
コード例 #7
0
        public DateTimeParseResult Parse(ExtractResult er, DateObject refTime)
        {
            var referenceTime      = refTime;
            DateTimeParseResult pr = null;

            var originText = er.Text;

            if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0)
            {
                er.Text    = MatchingUtil.PreProcessTextRemoveSuperfluousWords(er.Text, Config.SuperfluousWordMatcher, out var _);
                er.Length += er.Text.Length - originText.Length;
            }

            // Push, save the MOD string
            bool hasBefore = false, hasAfter = false, hasSince = false, hasAround = false, hasDateAfter = false;

            // "InclusiveModifier" means MOD should include the start/end time
            // For example, cases like "on or later than", "earlier than or in" have inclusive modifier
            bool hasInclusiveModifier = false;
            var  modStr      = string.Empty;
            var  beforeMatch = Config.BeforeRegex.MatchBegin(er.Text, trim: true);
            var  afterMatch  = Config.AfterRegex.MatchBegin(er.Text, trim: true);
            var  sinceMatch  = Config.SinceRegex.MatchBegin(er.Text, trim: true);
            var  aroundMatch = Config.AroundRegex.MatchBegin(er.Text, trim: true);

            if (beforeMatch.Success)
            {
                hasBefore  = true;
                er.Start  += beforeMatch.Length;
                er.Length -= beforeMatch.Length;
                er.Text    = er.Text.Substring(beforeMatch.Length);
                modStr     = beforeMatch.Value;

                if (!string.IsNullOrEmpty(beforeMatch.Groups["include"].Value))
                {
                    hasInclusiveModifier = true;
                }
            }
            else if (afterMatch.Success)
            {
                hasAfter   = true;
                er.Start  += afterMatch.Length;
                er.Length -= afterMatch.Length;
                er.Text    = er.Text.Substring(afterMatch.Length);
                modStr     = afterMatch.Value;

                if (!string.IsNullOrEmpty(afterMatch.Groups["include"].Value))
                {
                    hasInclusiveModifier = true;
                }
            }
            else if (sinceMatch.Success)
            {
                hasSince   = true;
                er.Start  += sinceMatch.Length;
                er.Length -= sinceMatch.Length;
                er.Text    = er.Text.Substring(sinceMatch.Length);
                modStr     = sinceMatch.Value;
            }
            else if (aroundMatch.Success)
            {
                hasAround  = true;
                er.Start  += aroundMatch.Length;
                er.Length -= aroundMatch.Length;
                er.Text    = er.Text.Substring(aroundMatch.Length);
                modStr     = aroundMatch.Value;
            }
            else if ((er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD, StringComparison.Ordinal) && Config.YearRegex.Match(er.Text).Success) ||
                     er.Type.Equals(Constants.SYS_DATETIME_DATE, StringComparison.Ordinal) ||
                     er.Type.Equals(Constants.SYS_DATETIME_TIME, StringComparison.Ordinal))
            {
                // This has to be put at the end of the if, or cases like "before 2012" and "after 2012" would fall into this
                // 2012 or after/above
                // 3 pm or later
                var match = Config.SuffixAfter.MatchEnd(er.Text, trim: true);
                if (match.Success)
                {
                    hasDateAfter = true;
                    er.Length   -= match.Length;
                    er.Text      = er.Text.Substring(0, er.Length ?? 0);
                    modStr       = match.Value;
                }
            }

            pr = ParseResult(er, referenceTime);
            if (pr == null)
            {
                return(null);
            }

            // Pop, restore the MOD string
            if (hasBefore && (pr != null && pr.Value != null))
            {
                pr.Length += modStr.Length;
                pr.Start  -= modStr.Length;
                pr.Text    = modStr + pr.Text;
                var val = (DateTimeResolutionResult)pr.Value;

                if (!hasInclusiveModifier)
                {
                    val.Mod = CombineMod(val.Mod, Constants.BEFORE_MOD);
                }
                else
                {
                    val.Mod = CombineMod(val.Mod, Constants.UNTIL_MOD);
                }

                pr.Value = val;
            }

            if (hasAfter && (pr != null && pr.Value != null))
            {
                pr.Length += modStr.Length;
                pr.Start  -= modStr.Length;
                pr.Text    = modStr + pr.Text;
                var val = (DateTimeResolutionResult)pr.Value;

                if (!hasInclusiveModifier)
                {
                    val.Mod = CombineMod(val.Mod, Constants.AFTER_MOD);
                }
                else
                {
                    val.Mod = CombineMod(val.Mod, Constants.SINCE_MOD);
                }

                pr.Value = val;
            }

            if (hasSince && (pr != null && pr.Value != null))
            {
                pr.Length += modStr.Length;
                pr.Start  -= modStr.Length;
                pr.Text    = modStr + pr.Text;
                var val = (DateTimeResolutionResult)pr.Value;
                val.Mod  = CombineMod(val.Mod, Constants.SINCE_MOD);
                pr.Value = val;
            }

            if (hasAround && (pr != null && pr.Value != null))
            {
                pr.Length += modStr.Length;
                pr.Start  -= modStr.Length;
                pr.Text    = modStr + pr.Text;
                var val = (DateTimeResolutionResult)pr.Value;
                val.Mod  = CombineMod(val.Mod, Constants.APPROX_MOD);
                pr.Value = val;
            }

            if (hasDateAfter && (pr != null && pr.Value != null))
            {
                pr.Length += modStr.Length;
                pr.Text    = pr.Text + modStr;
                var val = (DateTimeResolutionResult)pr.Value;
                val.Mod  = CombineMod(val.Mod, Constants.SINCE_MOD);
                pr.Value = val;
                hasSince = true;
            }

            // For cases like "3 pm or later on monday"
            if ((pr != null && pr.Value != null) && Config.SuffixAfter.Match(pr.Text)?.Index != 0 &&
                pr.Type.Equals(Constants.SYS_DATETIME_DATETIME, StringComparison.Ordinal))
            {
                var val = (DateTimeResolutionResult)pr.Value;
                val.Mod  = CombineMod(val.Mod, Constants.SINCE_MOD);
                pr.Value = val;
                hasSince = true;
            }

            if ((Config.Options & DateTimeOptions.SplitDateAndTime) != 0 &&
                ((DateTimeResolutionResult)pr?.Value)?.SubDateTimeEntities != null)
            {
                if (pr != null)
                {
                    pr.Value = DateTimeResolutionForSplit(pr);
                }
            }
            else
            {
                var hasModifier = hasBefore || hasAfter || hasSince;
                pr = SetParseResult(pr, hasModifier);
            }

            // In this version, ExperimentalMode only cope with the "IncludePeriodEnd" case
            if ((this.Config.Options & DateTimeOptions.ExperimentalMode) != 0)
            {
                if (pr?.Metadata != null && pr.Metadata.PossiblyIncludePeriodEnd)
                {
                    pr = SetInclusivePeriodEnd(pr);
                }
            }

            if ((this.Config.Options & DateTimeOptions.EnablePreview) != 0)
            {
                pr.Length += originText.Length - pr.Text.Length;
                pr.Text    = originText;
            }

            return(pr);
        }
コード例 #8
0
 public DateTimeParseResult Parse(ExtractResult er, DateObject refDate)
 {
     return(null);
 }
コード例 #9
0
 private void StripInequalityDuration(ExtractResult er)
 {
     StripInequalityPrefix(er, Config.MoreThanRegex);
     StripInequalityPrefix(er, Config.LessThanRegex);
 }
コード例 #10
0
        public static List <Token> ExtractorDurationWithBeforeAndAfter(string text, ExtractResult er, List <Token> ret,
                                                                       IDateTimeUtilityConfiguration utilityConfiguration)
        {
            var pos = (int)er.Start + (int)er.Length;

            if (pos <= text.Length)
            {
                var afterString    = text.Substring(pos);
                var beforeString   = text.Substring(0, (int)er.Start);
                var isTimeDuration = utilityConfiguration.TimeUnitRegex.Match(er.Text).Success;

                if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.AgoRegex, out var index))
                {
                    // We don't support cases like "5 minutes from today" for now
                    // Cases like "5 minutes ago" or "5 minutes from now" are supported
                    // Cases like "2 days before today" or "2 weeks from today" are also supported
                    var isDayMatchInAfterString = utilityConfiguration.AgoRegex.Match(afterString).Groups["day"].Success;

                    if (!(isTimeDuration && isDayMatchInAfterString))
                    {
                        ret.Add(new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index));
                    }

                    if (utilityConfiguration.CheckBothBeforeAfter && !isDayMatchInAfterString)
                    {
                        // check if regex match is split between beforeString and afterString
                        string beforeAfterStr = beforeString + afterString.Substring(0, index);
                        if (MatchingUtil.GetAgoLaterIndexInBeforeString(beforeAfterStr, utilityConfiguration.AgoRegex, out var indexStart))
                        {
                            isDayMatchInAfterString = utilityConfiguration.AgoRegex.Match(beforeAfterStr).Groups["day"].Success;

                            if (isDayMatchInAfterString && !(isTimeDuration && isDayMatchInAfterString))
                            {
                                ret.Add(new Token(indexStart, (er.Start + er.Length ?? 0) + index));
                            }
                        }
                    }
                }
                else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.GetAgoLaterIndexInBeforeString(beforeString, utilityConfiguration.AgoRegex, out index))
                {
                    // Check also beforeString
                    var isDayMatchInBeforeString = utilityConfiguration.AgoRegex.Match(beforeString).Groups["day"].Success;
                    if (!(isTimeDuration && isDayMatchInBeforeString))
                    {
                        ret.Add(new Token(index, er.Start + er.Length ?? 0));
                    }
                }
                else if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.LaterRegex, out index) || (utilityConfiguration.CheckBothBeforeAfter &&
                                                                                                                    MatchingUtil.GetAgoLaterIndexInBeforeString(beforeString, utilityConfiguration.LaterRegex, out index)))
                {
                    Token tokAfter = null, tokBefore = null;
                    if (MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.LaterRegex, out index))
                    {
                        var isDayMatchInAfterString = utilityConfiguration.LaterRegex.Match(afterString).Groups["day"].Success;

                        if (!(isTimeDuration && isDayMatchInAfterString))
                        {
                            tokAfter = new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index);
                        }
                    }

                    // Check also beforeString
                    if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.GetAgoLaterIndexInBeforeString(beforeString, utilityConfiguration.LaterRegex, out index))
                    {
                        var isDayMatchInBeforeString = utilityConfiguration.LaterRegex.Match(beforeString).Groups["day"].Success;
                        if (!(isTimeDuration && isDayMatchInBeforeString))
                        {
                            tokBefore = new Token(index, er.Start + er.Length ?? 0);
                        }
                    }

                    if (tokAfter != null && tokBefore != null && tokBefore.Start + tokBefore.Length > tokAfter.Start)
                    {
                        // merge overlapping tokens
                        ret.Add(new Token(tokBefore.Start, tokAfter.Start + tokAfter.Length - tokBefore.Start));
                    }
                    else if (tokAfter != null)
                    {
                        ret.Add(tokAfter);
                    }
                    else if (tokBefore != null)
                    {
                        ret.Add(tokBefore);
                    }
                }
                else if (MatchingUtil.GetTermIndex(beforeString, utilityConfiguration.InConnectorRegex, out index))
                {
                    // For range unit like "week, month, year", it should output dateRange or datetimeRange
                    if (!utilityConfiguration.RangeUnitRegex.IsMatch(er.Text))
                    {
                        if (er.Start != null && er.Length != null && (int)er.Start >= index)
                        {
                            ret.Add(new Token((int)er.Start - index, (int)er.Start + (int)er.Length));
                        }
                    }
                }
                else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.InConnectorRegex, out index))
                {
                    // Check also afterString
                    // For range unit like "week, month, year", it should output dateRange or datetimeRange
                    if (!utilityConfiguration.RangeUnitRegex.IsMatch(er.Text))
                    {
                        if (er.Start != null && er.Length != null)
                        {
                            ret.Add(new Token((int)er.Start, (int)er.Start + (int)er.Length + index));
                        }
                    }
                }
                else if (MatchingUtil.GetTermIndex(beforeString, utilityConfiguration.WithinNextPrefixRegex, out index))
                {
                    // For range unit like "week, month, year, day, second, minute, hour", it should output dateRange or datetimeRange
                    if (!utilityConfiguration.DateUnitRegex.IsMatch(er.Text) && !utilityConfiguration.TimeUnitRegex.IsMatch(er.Text))
                    {
                        if (er.Start != null && er.Length != null && (int)er.Start >= index)
                        {
                            ret.Add(new Token((int)er.Start - index, (int)er.Start + (int)er.Length));
                        }
                    }
                }
                else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.GetAgoLaterIndex(afterString, utilityConfiguration.WithinNextPrefixRegex, out index))
                {
                    // Check also afterString
                    // For range unit like "week, month, year, day, second, minute, hour", it should output dateRange or datetimeRange
                    if (!utilityConfiguration.DateUnitRegex.IsMatch(er.Text) && !utilityConfiguration.TimeUnitRegex.IsMatch(er.Text))
                    {
                        if (er.Start != null && er.Length != null)
                        {
                            ret.Add(new Token((int)er.Start, (int)er.Start + (int)er.Length + index));
                        }
                    }
                }
            }

            return(ret);
        }
コード例 #11
0
        public DateTimeParseResult Parse(ExtractResult er, DateObject refDate)
        {
            var referenceTime = refDate;

            object value = null;

            if (er.Type.Equals(ParserName, StringComparison.Ordinal))
            {
                var innerResult = MergeDateAndTimePeriod(er.Text, referenceTime);
                if (!innerResult.Success)
                {
                    innerResult = MergeTwoTimePoints(er.Text, referenceTime);
                }

                if (!innerResult.Success)
                {
                    innerResult = ParseSpecificNight(er.Text, referenceTime);
                }

                if (!innerResult.Success)
                {
                    innerResult = ParseNumberWithUnit(er.Text, referenceTime);
                }

                if (innerResult.Success)
                {
                    innerResult.FutureResolution = new Dictionary <string, string>
                    {
                        {
                            TimeTypeConstants.START_DATETIME,
                            DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item1)
                        },
                        {
                            TimeTypeConstants.END_DATETIME,
                            DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item2)
                        },
                    };

                    innerResult.PastResolution = new Dictionary <string, string>
                    {
                        {
                            TimeTypeConstants.START_DATETIME,
                            DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item1)
                        },
                        {
                            TimeTypeConstants.END_DATETIME,
                            DateTimeFormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item2)
                        },
                    };

                    value = innerResult;
                }
            }

            var ret = new DateTimeParseResult
            {
                Text          = er.Text,
                Start         = er.Start,
                Length        = er.Length,
                Type          = er.Type,
                Data          = er.Data,
                Value         = value,
                TimexStr      = value == null ? string.Empty : ((DateTimeResolutionResult)value).Timex,
                ResolutionStr = string.Empty,
            };

            return(ret);
        }
コード例 #12
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);
        }
コード例 #13
0
 public static bool IsCover(this ExtractResult er1, ExtractResult er2)
 {
     return(er2.Start < er1.Start && er2.Start + er2.Length >= er1.Start + er1.Length ||
            er2.Start <= er1.Start && er2.Start + er2.Length > er1.Start + er1.Length);
 }
コード例 #14
0
 public static bool IsOverlap(this ExtractResult er1, ExtractResult er2)
 {
     return(!(er1.Start >= er2.Start + er2.Length) && !(er2.Start >= er1.Start + er1.Length));
 }
コード例 #15
0
        public DateTimeParseResult Parse(ExtractResult er, DateObject refTime)
        {
            var referenceTime = refTime;

            object value = null;

            if (er.Type.Equals(ParserName, StringComparison.Ordinal))
            {
                DateTimeResolutionResult innerResult;

                if (TimeZoneUtility.ShouldResolveTimeZone(er, config.Options))
                {
                    var metadata   = er.Data as Dictionary <string, object>;
                    var timezoneEr = metadata[Constants.SYS_DATETIME_TIMEZONE] as ExtractResult;
                    var timezonePr = config.TimeZoneParser.Parse(timezoneEr);

                    innerResult = InternalParse(
                        er.Text.Substring(0, (int)(er.Length - timezoneEr.Length)),
                        referenceTime);

                    if (timezonePr != null && timezonePr.Value != null)
                    {
                        innerResult.TimeZoneResolution = ((DateTimeResolutionResult)timezonePr.Value).TimeZoneResolution;
                    }
                }
                else
                {
                    innerResult = InternalParse(er.Text, referenceTime);
                }

                if (innerResult.Success)
                {
                    innerResult.FutureResolution = new Dictionary <string, string>
                    {
                        {
                            TimeTypeConstants.START_TIME,
                            DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item1)
                        },
                        {
                            TimeTypeConstants.END_TIME,
                            DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.FutureValue).Item2)
                        },
                    };

                    innerResult.PastResolution = new Dictionary <string, string>
                    {
                        {
                            TimeTypeConstants.START_TIME,
                            DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item1)
                        },
                        {
                            TimeTypeConstants.END_TIME,
                            DateTimeFormatUtil.FormatTime(((Tuple <DateObject, DateObject>)innerResult.PastValue).Item2)
                        },
                    };

                    value = innerResult;
                }
            }

            var ret = new DateTimeParseResult
            {
                Text          = er.Text,
                Start         = er.Start,
                Length        = er.Length,
                Type          = er.Type,
                Data          = er.Data,
                Value         = value,
                TimexStr      = value == null ? string.Empty : ((DateTimeResolutionResult)value).Timex,
                ResolutionStr = string.Empty,
            };

            return(ret);
        }
コード例 #16
0
 private bool IsDurationWithBeforeAndAfter(ExtractResult er)
 {
     return(er.Metadata != null && er.Metadata.IsDurationWithBeforeAndAfter);
 }
コード例 #17
0
        // Cases like "from 3:30 to 5" or "between 3:30am to 6pm", at least one of the time point contains colon
        private DateTimeResolutionResult ParseSpecificTimeCases(string text, DateObject referenceTime)
        {
            var ret = new DateTimeResolutionResult();
            int year = referenceTime.Year, month = referenceTime.Month, day = referenceTime.Day;

            // Handle cases like "from 4:30 to 5"
            var match = config.SpecificTimeFromToRegex.MatchExact(text, trim: true);

            if (!match.Success)
            {
                // Handle cases like "between 5:10 and 7"
                match = config.SpecificTimeBetweenAndRegex.MatchExact(text, trim: true);
            }

            if (match.Success)
            {
                // Cases like "half past seven" are not handled here
                if (match.Groups[Constants.PrefixGroupName].Success)
                {
                    return(ret);
                }

                // Cases like "4" is different with "4:00" as the Timex is different "T04H" vs "T04H00M"
                int beginHour;
                int beginMinute = Constants.InvalidMinute;
                int beginSecond = Constants.InvalidSecond;
                int endHour;
                int endMinute = Constants.InvalidMinute;
                int endSecond = Constants.InvalidSecond;

                // Get time1 and time2
                var hourGroup = match.Groups[Constants.HourGroupName];

                var hourStr = hourGroup.Captures[0].Value;

                if (config.Numbers.ContainsKey(hourStr))
                {
                    beginHour = config.Numbers[hourStr];
                }
                else
                {
                    beginHour = int.Parse(hourStr, CultureInfo.InvariantCulture);
                }

                hourStr = hourGroup.Captures[1].Value;

                if (config.Numbers.ContainsKey(hourStr))
                {
                    endHour = config.Numbers[hourStr];
                }
                else
                {
                    endHour = int.Parse(hourStr, CultureInfo.InvariantCulture);
                }

                var time1StartIndex = match.Groups["time1"].Index;
                var time1EndIndex   = time1StartIndex + match.Groups["time1"].Length;
                var time2StartIndex = match.Groups["time2"].Index;
                var time2EndIndex   = time2StartIndex + match.Groups["time2"].Length;

                // Get beginMinute (if exists) and endMinute (if exists)
                for (int i = 0; i < match.Groups[Constants.MinuteGroupName].Captures.Count; i++)
                {
                    var minuteCapture = match.Groups[Constants.MinuteGroupName].Captures[i];
                    if (minuteCapture.Index >= time1StartIndex && minuteCapture.Index + minuteCapture.Length <= time1EndIndex)
                    {
                        beginMinute = int.Parse(minuteCapture.Value, CultureInfo.InvariantCulture);
                    }
                    else if (minuteCapture.Index >= time2StartIndex && minuteCapture.Index + minuteCapture.Length <= time2EndIndex)
                    {
                        endMinute = int.Parse(minuteCapture.Value, CultureInfo.InvariantCulture);
                    }
                }

                // Get beginSecond (if exists) and endSecond (if exists)
                for (int i = 0; i < match.Groups[Constants.SecondGroupName].Captures.Count; i++)
                {
                    var secondCapture = match.Groups[Constants.SecondGroupName].Captures[i];
                    if (secondCapture.Index >= time1StartIndex && secondCapture.Index + secondCapture.Length <= time1EndIndex)
                    {
                        beginSecond = int.Parse(secondCapture.Value, CultureInfo.InvariantCulture);
                    }
                    else if (secondCapture.Index >= time2StartIndex && secondCapture.Index + secondCapture.Length <= time2EndIndex)
                    {
                        endSecond = int.Parse(secondCapture.Value, CultureInfo.InvariantCulture);
                    }
                }

                // Desc here means descriptions like "am / pm / o'clock"
                // Get leftDesc (if exists) and rightDesc (if exists)
                var leftDesc  = match.Groups["leftDesc"].Value;
                var rightDesc = match.Groups["rightDesc"].Value;

                for (int i = 0; i < match.Groups[Constants.DescGroupName].Captures.Count; i++)
                {
                    var descCapture = match.Groups[Constants.DescGroupName].Captures[i];
                    if (descCapture.Index >= time1StartIndex && descCapture.Index + descCapture.Length <= time1EndIndex && string.IsNullOrEmpty(leftDesc))
                    {
                        leftDesc = descCapture.Value;
                    }
                    else if (descCapture.Index >= time2StartIndex && descCapture.Index + descCapture.Length <= time2EndIndex && string.IsNullOrEmpty(rightDesc))
                    {
                        rightDesc = descCapture.Value;
                    }
                }

                var beginDateTime = DateObject.MinValue.SafeCreateFromValue(year, month, day, beginHour, beginMinute >= 0 ? beginMinute : 0, beginSecond >= 0 ? beginSecond : 0);
                var endDateTime   = DateObject.MinValue.SafeCreateFromValue(year, month, day, endHour, endMinute >= 0 ? endMinute : 0, endSecond >= 0 ? endSecond : 0);

                var hasLeftAm  = !string.IsNullOrEmpty(leftDesc) && leftDesc.StartsWith("a", StringComparison.Ordinal);
                var hasLeftPm  = !string.IsNullOrEmpty(leftDesc) && leftDesc.StartsWith("p", StringComparison.Ordinal);
                var hasRightAm = !string.IsNullOrEmpty(rightDesc) && rightDesc.StartsWith("a", StringComparison.Ordinal);
                var hasRightPm = !string.IsNullOrEmpty(rightDesc) && rightDesc.StartsWith("p", StringComparison.Ordinal);
                var hasLeft    = hasLeftAm || hasLeftPm;
                var hasRight   = hasRightAm || hasRightPm;

                // Both time point has description like 'am' or 'pm'
                if (hasLeft && hasRight)
                {
                    if (hasLeftAm)
                    {
                        if (beginHour >= Constants.HalfDayHourCount)
                        {
                            beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount);
                        }
                    }
                    else
                    {
                        if (beginHour < Constants.HalfDayHourCount)
                        {
                            beginDateTime = beginDateTime.AddHours(Constants.HalfDayHourCount);
                        }
                    }

                    if (hasRightAm)
                    {
                        if (endHour > Constants.HalfDayHourCount)
                        {
                            endDateTime = endDateTime.AddHours(-Constants.HalfDayHourCount);
                        }
                    }
                    else
                    {
                        if (endHour < Constants.HalfDayHourCount)
                        {
                            endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount);
                        }
                    }
                }
                else if (hasLeft || hasRight)
                {
                    // one of the time point has description like 'am' or 'pm'
                    if (hasLeftAm)
                    {
                        if (beginHour >= Constants.HalfDayHourCount)
                        {
                            beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount);
                        }

                        if (endHour < Constants.HalfDayHourCount)
                        {
                            if (endDateTime < beginDateTime)
                            {
                                endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount);
                            }
                        }
                    }
                    else if (hasLeftPm)
                    {
                        if (beginHour < Constants.HalfDayHourCount)
                        {
                            beginDateTime = beginDateTime.AddHours(Constants.HalfDayHourCount);
                        }

                        if (endHour < Constants.HalfDayHourCount)
                        {
                            if (endDateTime < beginDateTime)
                            {
                                var span = beginDateTime - endDateTime;
                                endDateTime = endDateTime.AddHours(span.TotalHours >= Constants.HalfDayHourCount ?
                                                                   24 :
                                                                   Constants.HalfDayHourCount);
                            }
                        }
                    }

                    if (hasRightAm)
                    {
                        if (endHour >= Constants.HalfDayHourCount)
                        {
                            endDateTime = endDateTime.AddHours(-Constants.HalfDayHourCount);
                        }

                        if (beginHour < Constants.HalfDayHourCount)
                        {
                            if (endDateTime < beginDateTime)
                            {
                                beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount);
                            }
                        }
                    }
                    else if (hasRightPm)
                    {
                        if (endHour < Constants.HalfDayHourCount)
                        {
                            endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount);
                        }

                        if (beginHour < Constants.HalfDayHourCount)
                        {
                            if (endDateTime < beginDateTime)
                            {
                                beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount);
                            }
                            else
                            {
                                var span = endDateTime - beginDateTime;
                                if (span.TotalHours > Constants.HalfDayHourCount)
                                {
                                    beginDateTime = beginDateTime.AddHours(Constants.HalfDayHourCount);
                                }
                            }
                        }
                    }
                }

                // No 'am' or 'pm' indicator
                else if (beginHour <= Constants.HalfDayHourCount && endHour <= Constants.HalfDayHourCount)
                {
                    if (beginHour > endHour)
                    {
                        if (beginHour == Constants.HalfDayHourCount)
                        {
                            beginDateTime = beginDateTime.AddHours(-Constants.HalfDayHourCount);
                        }
                        else
                        {
                            endDateTime = endDateTime.AddHours(Constants.HalfDayHourCount);
                        }
                    }

                    ret.Comment = Constants.Comment_AmPm;
                }

                if (endDateTime < beginDateTime)
                {
                    endDateTime = endDateTime.AddHours(24);
                }

                var beginStr = DateTimeFormatUtil.ShortTime(beginDateTime.Hour, beginMinute, beginSecond);
                var endStr   = DateTimeFormatUtil.ShortTime(endDateTime.Hour, endMinute, endSecond);

                ret.Success = true;

                ret.Timex = $"({beginStr},{endStr},{DateTimeFormatUtil.LuisTimeSpan(endDateTime - beginDateTime)})";

                ret.FutureValue = ret.PastValue = new Tuple <DateObject, DateObject>(
                    beginDateTime,
                    endDateTime);

                ret.SubDateTimeEntities = new List <object>();

                // In SplitDateAndTime mode, time points will be get from these SubDateTimeEntities
                // Cases like "from 4 to 5pm", "4" should not be treated as SubDateTimeEntity
                if (hasLeft || beginMinute != Constants.InvalidMinute || beginSecond != Constants.InvalidSecond)
                {
                    var er = new ExtractResult()
                    {
                        Start  = time1StartIndex,
                        Length = time1EndIndex - time1StartIndex,
                        Text   = text.Substring(time1StartIndex, time1EndIndex - time1StartIndex),
                        Type   = $"{Constants.SYS_DATETIME_TIME}",
                    };

                    var pr = this.config.TimeParser.Parse(er, referenceTime);
                    ret.SubDateTimeEntities.Add(pr);
                }

                // Cases like "from 4am to 5", "5" should not be treated as SubDateTimeEntity
                if (hasRight || endMinute != Constants.InvalidMinute || endSecond != Constants.InvalidSecond)
                {
                    var er = new ExtractResult
                    {
                        Start  = time2StartIndex,
                        Length = time2EndIndex - time2StartIndex,
                        Text   = text.Substring(time2StartIndex, time2EndIndex - time2StartIndex),
                        Type   = $"{Constants.SYS_DATETIME_TIME}",
                    };

                    var pr = this.config.TimeParser.Parse(er, referenceTime);
                    ret.SubDateTimeEntities.Add(pr);
                }

                ret.Success = true;
            }

            return(ret);
        }
コード例 #18
0
 private bool ShouldSkipFromToMerge(ExtractResult er)
 {
     return(config.FromToRegex.IsMatch(er.Text));
 }
コード例 #19
0
 public ParseResult Parse(ExtractResult er)
 {
     return(Parse(er, DateObject.Now));
 }
コード例 #20
0
        // Merge a Date entity and a Time entity, like "at 7 tomorrow"
        public List <Token> MergeDateAndTime(string text, DateObject reference)
        {
            var ret     = new List <Token>();
            var dateErs = this.config.DatePointExtractor.Extract(text, reference);

            if (dateErs.Count == 0)
            {
                return(ret);
            }

            var timeErs        = this.config.TimePointExtractor.Extract(text, reference);
            var timeNumMatches = this.config.NumberAsTimeRegex.Matches(text);

            if (timeErs.Count == 0 && timeNumMatches.Count == 0)
            {
                return(ret);
            }

            var ers = dateErs;

            ers.AddRange(timeErs);

            // handle cases which use numbers as time points
            // only enabled in CalendarMode
            if ((this.config.Options & DateTimeOptions.CalendarMode) != 0)
            {
                var numErs = new List <ExtractResult>();
                for (var idx = 0; idx < timeNumMatches.Count; idx++)
                {
                    var match = timeNumMatches[idx];
                    var node  = new ExtractResult
                    {
                        Start  = match.Index,
                        Length = match.Length,
                        Text   = match.Value,
                        Type   = Number.Constants.SYS_NUM_INTEGER,
                    };

                    numErs.Add(node);
                }

                ers.AddRange(numErs);
            }

            ers = ers.OrderBy(o => o.Start).ToList();

            var i = 0;

            while (i < ers.Count - 1)
            {
                var j = i + 1;
                while (j < ers.Count && ers[i].IsOverlap(ers[j]))
                {
                    j++;
                }

                if (j >= ers.Count)
                {
                    break;
                }

                if ((ers[i].Type.Equals(Constants.SYS_DATETIME_DATE, StringComparison.Ordinal) &&
                     ers[j].Type.Equals(Constants.SYS_DATETIME_TIME, StringComparison.Ordinal)) ||
                    (ers[i].Type.Equals(Constants.SYS_DATETIME_TIME, StringComparison.Ordinal) &&
                     ers[j].Type.Equals(Constants.SYS_DATETIME_DATE, StringComparison.Ordinal)) ||
                    (ers[i].Type.Equals(Constants.SYS_DATETIME_DATE, StringComparison.Ordinal) &&
                     ers[j].Type.Equals(Number.Constants.SYS_NUM_INTEGER, StringComparison.Ordinal)))
                {
                    var middleBegin = ers[i].Start + ers[i].Length ?? 0;
                    var middleEnd   = ers[j].Start ?? 0;
                    if (middleBegin > middleEnd)
                    {
                        i = j + 1;
                        continue;
                    }

                    var middleStr = text.Substring(middleBegin, middleEnd - middleBegin).Trim();
                    var valid     = false;

                    // for cases like "tomorrow 3",  "tomorrow at 3"
                    if (ers[j].Type.Equals(Number.Constants.SYS_NUM_INTEGER, StringComparison.Ordinal))
                    {
                        var match = this.config.DateNumberConnectorRegex.Match(middleStr);
                        if (string.IsNullOrEmpty(middleStr) || match.Success)
                        {
                            valid = true;
                        }
                    }
                    else
                    {
                        // For case like "3 pm or later on monday"
                        var match = this.config.SuffixAfterRegex.Match(middleStr);
                        if (match.Success)
                        {
                            middleStr = middleStr.Substring(match.Index + match.Length, middleStr.Length - match.Length).Trim();
                        }

                        if (!(match.Success && middleStr.Length == 0))
                        {
                            if (this.config.IsConnector(middleStr))
                            {
                                valid = true;
                            }
                        }
                    }

                    if (valid)
                    {
                        var begin = ers[i].Start ?? 0;
                        var end   = (ers[j].Start ?? 0) + (ers[j].Length ?? 0);

                        ExtendWithDateTimeAndYear(ref begin, ref end, text, reference);

                        ret.Add(new Token(begin, end));
                        i = j + 1;
                        continue;
                    }
                }

                i = j;
            }

            // Handle "in the afternoon" at the end of entity
            for (var idx = 0; idx < ret.Count; idx++)
            {
                var afterStr = text.Substring(ret[idx].End);
                var match    = this.config.SuffixRegex.Match(afterStr);
                if (match.Success)
                {
                    ret[idx] = new Token(ret[idx].Start, ret[idx].End + match.Length);
                }
            }

            // Handle "day" prefixes
            for (var idx = 0; idx < ret.Count; idx++)
            {
                var beforeStr = text.Substring(0, ret[idx].Start);
                var match     = this.config.UtilityConfiguration.CommonDatePrefixRegex.Match(beforeStr);
                if (match.Success)
                {
                    ret[idx] = new Token(ret[idx].Start - match.Length, ret[idx].End);
                }
            }

            return(ret);
        }
コード例 #21
0
        private DateTimeParseResult ParseResult(ExtractResult extractResult, DateObject referenceTime)
        {
            DateTimeParseResult parseResult = null;

            switch (extractResult.Type)
            {
            case Constants.SYS_DATETIME_DATE:
                if (extractResult.Metadata != null && extractResult.Metadata.IsHoliday)
                {
                    parseResult = Config.HolidayParser.Parse(extractResult, referenceTime);
                }
                else
                {
                    parseResult = this.Config.DateParser.Parse(extractResult, referenceTime);
                }

                break;

            case Constants.SYS_DATETIME_TIME:
                parseResult = this.Config.TimeParser.Parse(extractResult, referenceTime);

                break;

            case Constants.SYS_DATETIME_DATETIME:
                parseResult = this.Config.DateTimeParser.Parse(extractResult, referenceTime);

                break;

            case Constants.SYS_DATETIME_DATEPERIOD:
                parseResult = this.Config.DatePeriodParser.Parse(extractResult, referenceTime);

                break;

            case Constants.SYS_DATETIME_TIMEPERIOD:
                parseResult = this.Config.TimePeriodParser.Parse(extractResult, referenceTime);

                break;

            case Constants.SYS_DATETIME_DATETIMEPERIOD:
                parseResult = this.Config.DateTimePeriodParser.Parse(extractResult, referenceTime);

                break;

            case Constants.SYS_DATETIME_DURATION:
                parseResult = this.Config.DurationParser.Parse(extractResult, referenceTime);

                break;

            case Constants.SYS_DATETIME_SET:
                parseResult = this.Config.SetParser.Parse(extractResult, referenceTime);

                break;

            case Constants.SYS_DATETIME_DATETIMEALT:
                parseResult = this.Config.DateTimeAltParser.Parse(extractResult, referenceTime);

                break;

            case Constants.SYS_DATETIME_TIMEZONE:
                if ((Config.Options & DateTimeOptions.EnablePreview) != 0)
                {
                    parseResult = this.Config.TimeZoneParser.Parse(extractResult, referenceTime);
                }

                break;

            default:
                return(null);
            }

            return(parseResult);
        }
コード例 #22
0
        public DateTimeParseResult Parse(ExtractResult er, DateObject refDate)
        {
            var referenceTime = refDate;

            // handle cases like "三年半"
            var hasHalfSuffix = false;

            if (er.Text.EndsWith("半"))
            {
                er.Length    -= 1;
                er.Text       = er.Text.Substring(0, er.Text.Length - 1);
                hasHalfSuffix = true;
            }

            var parseResult = InternalParser.Parse(er);
            var unitResult  = parseResult.Value as UnitValue;

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

            var dateTimeParseResult = new DateTimeResolutionResult();
            var unitStr             = unitResult.Unit;
            var numStr = unitResult.Number;

            if (hasHalfSuffix)
            {
                numStr = (double.Parse(numStr) + 0.5).ToString(CultureInfo.InvariantCulture);
            }

            dateTimeParseResult.Timex       = "P" + (BaseDurationParser.IsLessThanDay(unitStr) ? "T" : string.Empty) + numStr + unitStr[0];
            dateTimeParseResult.FutureValue = dateTimeParseResult.PastValue = double.Parse(numStr) * 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() },
                };
            }

            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);
        }
コード例 #23
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);
        }
コード例 #24
0
        public DateTimeParseResult Parse(ExtractResult er, DateObject refTime)
        {
            var referenceTime = refTime;

            object value = null;

            if (er.Type.Equals(ParserName, StringComparison.Ordinal))
            {
                var innerResult = ParseMergedDuration(er.Text, referenceTime);
                if (!innerResult.Success)
                {
                    innerResult = ParseNumberWithUnit(er.Text, referenceTime);
                }

                if (!innerResult.Success)
                {
                    innerResult = ParseImplicitDuration(er.Text, referenceTime);
                }

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

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

                    value = innerResult;
                }
            }

            var res = (DateTimeResolutionResult)value;

            if (res != null && er.Data != null)
            {
                if (er.Data.Equals(Constants.MORE_THAN_MOD))
                {
                    res.Mod = Constants.MORE_THAN_MOD;
                }
                else if (er.Data.Equals(Constants.LESS_THAN_MOD))
                {
                    res.Mod = Constants.LESS_THAN_MOD;
                }
            }

            var ret = new DateTimeParseResult
            {
                Text          = er.Text,
                Start         = er.Start,
                Length        = er.Length,
                Type          = er.Type,
                Data          = er.Data,
                Value         = value,
                TimexStr      = value == null ? string.Empty : ((DateTimeResolutionResult)value).Timex,
                ResolutionStr = string.Empty,
            };

            return(ret);
        }
コード例 #25
0
        public DateTimeParseResult Parse(ExtractResult er, DateObject referenceTime)
        {
            DateTimeParseResult pr = null;

            // push, save teh MOD string
            bool   hasBefore = false, hasAfter = false, hasUntil = false, hasSince = false;
            string modStr = string.Empty, modStrPrefix = string.Empty, modStrSuffix = string.Empty;
            var    beforeMatch      = config.BeforeRegex.Match(er.Text);
            var    afterMatch       = config.AfterRegex.Match(er.Text);
            var    untilMatch       = config.UntilRegex.Match(er.Text);
            var    sinceMatchPrefix = config.SincePrefixRegex.Match(er.Text);
            var    sinceMatchSuffix = config.SinceSuffixRegex.Match(er.Text);

            if (beforeMatch.Success && er.Text.EndsWith(beforeMatch.Value))
            {
                hasBefore  = true;
                er.Length -= beforeMatch.Length;
                er.Text    = er.Text.Substring(0, er.Length ?? 0);
                modStr     = beforeMatch.Value;
            }
            else if (afterMatch.Success && er.Text.EndsWith(afterMatch.Value))
            {
                hasAfter   = true;
                er.Length -= afterMatch.Length;
                er.Text    = er.Text.Substring(0, er.Length ?? 0);
                modStr     = afterMatch.Value;
            }
            else if (untilMatch.Success && untilMatch.Index == 0)
            {
                hasUntil   = true;
                er.Start  += untilMatch.Length;
                er.Length -= untilMatch.Length;
                er.Text    = er.Text.Substring(untilMatch.Length);
                modStr     = untilMatch.Value;
            }
            else
            {
                if (sinceMatchPrefix.Success && sinceMatchPrefix.Index == 0)
                {
                    hasSince     = true;
                    er.Start    += sinceMatchPrefix.Length;
                    er.Length   -= sinceMatchPrefix.Length;
                    er.Text      = er.Text.Substring(sinceMatchPrefix.Length);
                    modStrPrefix = sinceMatchPrefix.Value;
                }

                if (sinceMatchSuffix.Success && er.Text.EndsWith(sinceMatchSuffix.Value))
                {
                    hasSince     = true;
                    er.Length   -= sinceMatchSuffix.Length;
                    er.Text      = er.Text.Substring(0, er.Length ?? 0);
                    modStrSuffix = sinceMatchSuffix.Value;
                }
            }

            if (er.Type.Equals(Constants.SYS_DATETIME_DATE))
            {
                pr = config.DateParser.Parse(er, referenceTime);
                if (pr.Value == null)
                {
                    pr = config.HolidayParser.Parse(er, referenceTime);
                }
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_TIME))
            {
                pr = config.TimeParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIME))
            {
                pr = config.DateTimeParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD))
            {
                pr = config.DatePeriodParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_TIMEPERIOD))
            {
                pr = config.TimePeriodParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_DATETIMEPERIOD))
            {
                pr = config.DateTimePeriodParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_DURATION))
            {
                pr = config.DurationParser.Parse(er, referenceTime);
            }
            else if (er.Type.Equals(Constants.SYS_DATETIME_SET))
            {
                pr = config.GetParser.Parse(er, referenceTime);
            }
            else
            {
                return(null);
            }

            // pop, restore the MOD string
            if (hasBefore)
            {
                pr.Length += modStr.Length;
                pr.Text    = pr.Text + modStr;
                var val = (DateTimeResolutionResult)pr.Value;
                val.Mod  = Constants.BEFORE_MOD;
                pr.Value = val;
            }

            if (hasAfter)
            {
                pr.Length += modStr.Length;
                pr.Text    = pr.Text + modStr;
                var val = (DateTimeResolutionResult)pr.Value;
                val.Mod  = Constants.AFTER_MOD;
                pr.Value = val;
            }

            if (hasUntil)
            {
                pr.Length += modStr.Length;
                pr.Start  -= modStr.Length;
                pr.Text    = modStr + pr.Text;
                var val = (DateTimeResolutionResult)pr.Value;
                val.Mod   = Constants.BEFORE_MOD;
                pr.Value  = val;
                hasBefore = true;
            }

            if (hasSince)
            {
                pr.Length += modStrPrefix.Length + modStrSuffix.Length;
                pr.Start  -= modStrPrefix.Length;
                pr.Text    = modStrPrefix + pr.Text + modStrSuffix;
                var val = (DateTimeResolutionResult)pr.Value;
                val.Mod  = Constants.SINCE_MOD;
                pr.Value = val;
            }

            pr.Value = DateTimeResolution(pr, hasBefore, hasAfter, hasSince);

            //change the type at last for the after or before mode
            pr.Type = $"{ParserTypeName}.{DetermineDateTimeType(er.Type, hasBefore, hasAfter, hasSince)}";

            return(pr);
        }
コード例 #26
0
        private void GetResolution(ExtractResult er, DateTimeParseResult pr, DateTimeResolutionResult ret)
        {
            var parentText = (string)((Dictionary <string, object>)er.Data)[ExtendedModelResult.ParentTextKey];
            var type       = pr.Type;

            var    isPeriod                   = false;
            var    isSinglePoint              = false;
            string singlePointResolution      = "";
            string pastStartPointResolution   = "";
            string pastEndPointResolution     = "";
            string futureStartPointResolution = "";
            string futureEndPointResolution   = "";
            string singlePointType            = "";
            string startPointType             = "";
            string endPointType               = "";

            if (type == Constants.SYS_DATETIME_DATEPERIOD || type == Constants.SYS_DATETIME_TIMEPERIOD ||
                type == Constants.SYS_DATETIME_DATETIMEPERIOD)
            {
                isPeriod = true;
                switch (type)
                {
                case Constants.SYS_DATETIME_DATEPERIOD:
                    startPointType             = TimeTypeConstants.START_DATE;
                    endPointType               = TimeTypeConstants.END_DATE;
                    pastStartPointResolution   = FormatUtil.FormatDate(((Tuple <DateObject, DateObject>)ret.PastValue).Item1);
                    pastEndPointResolution     = FormatUtil.FormatDate(((Tuple <DateObject, DateObject>)ret.PastValue).Item2);
                    futureStartPointResolution = FormatUtil.FormatDate(((Tuple <DateObject, DateObject>)ret.FutureValue).Item1);
                    futureEndPointResolution   = FormatUtil.FormatDate(((Tuple <DateObject, DateObject>)ret.FutureValue).Item2);
                    break;

                case Constants.SYS_DATETIME_DATETIMEPERIOD:
                    startPointType             = TimeTypeConstants.START_DATETIME;
                    endPointType               = TimeTypeConstants.END_DATETIME;
                    pastStartPointResolution   = FormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)ret.PastValue).Item1);
                    pastEndPointResolution     = FormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)ret.PastValue).Item2);
                    futureStartPointResolution = FormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)ret.FutureValue).Item1);
                    futureEndPointResolution   = FormatUtil.FormatDateTime(((Tuple <DateObject, DateObject>)ret.FutureValue).Item2);
                    break;

                case Constants.SYS_DATETIME_TIMEPERIOD:
                    startPointType             = TimeTypeConstants.START_TIME;
                    endPointType               = TimeTypeConstants.END_TIME;
                    pastStartPointResolution   = FormatUtil.FormatTime(((Tuple <DateObject, DateObject>)ret.PastValue).Item1);
                    pastEndPointResolution     = FormatUtil.FormatTime(((Tuple <DateObject, DateObject>)ret.PastValue).Item2);
                    futureStartPointResolution = FormatUtil.FormatTime(((Tuple <DateObject, DateObject>)ret.FutureValue).Item1);
                    futureEndPointResolution   = FormatUtil.FormatTime(((Tuple <DateObject, DateObject>)ret.FutureValue).Item2);
                    break;
                }
            }
            else
            {
                isSinglePoint = true;
                switch (type)
                {
                case Constants.SYS_DATETIME_DATE:
                    singlePointType       = TimeTypeConstants.DATE;
                    singlePointResolution = FormatUtil.FormatDate((DateObject)ret.FutureValue);
                    break;

                case Constants.SYS_DATETIME_DATETIME:
                    singlePointType       = TimeTypeConstants.DATETIME;
                    singlePointResolution = FormatUtil.FormatDateTime((DateObject)ret.FutureValue);
                    break;

                case Constants.SYS_DATETIME_TIME:
                    singlePointType       = TimeTypeConstants.TIME;
                    singlePointResolution = FormatUtil.FormatTime((DateObject)ret.FutureValue);
                    break;
                }
            }

            if (isPeriod)
            {
                ret.FutureResolution = new Dictionary <string, string>
                {
                    { startPointType, futureStartPointResolution },
                    { endPointType, futureEndPointResolution },
                    { ExtendedModelResult.ParentTextKey, parentText }
                };

                ret.PastResolution = new Dictionary <string, string>
                {
                    { startPointType, pastStartPointResolution },
                    { endPointType, pastEndPointResolution },
                    { ExtendedModelResult.ParentTextKey, parentText }
                };
            }
            else if (isSinglePoint)
            {
                ret.FutureResolution = new Dictionary <string, string>
                {
                    { singlePointType, singlePointResolution },
                    { ExtendedModelResult.ParentTextKey, parentText }
                };

                ret.PastResolution = new Dictionary <string, string>
                {
                    { singlePointType, singlePointResolution },
                    { ExtendedModelResult.ParentTextKey, parentText }
                };
            }
        }
コード例 #27
0
 private static bool IsMultipleDuration(ExtractResult er)
 {
     return(er.Data != null && er.Data.ToString().StartsWith(Constants.MultipleDuration_Prefix, StringComparison.Ordinal));
 }
コード例 #28
0
        // merge the entity with its related contexts and then parse the combine text
        private DateTimeResolutionResult ParseDateTimeAndTimeAlt(ExtractResult er, DateObject referenceTime)
        {
            var ret = new DateTimeResolutionResult();

            // Original type of the extracted entity
            var subType    = ((Dictionary <string, object>)(er.Data))[Constants.SubType].ToString();
            var dateTimeEr = new ExtractResult();

            // e.g. {next week Mon} or {Tue}, formmer--"next week Mon" doesn't contain "context" key
            var           hasContext = false;
            ExtractResult contextEr  = null;

            if (((Dictionary <string, object>)er.Data).ContainsKey(Constants.Context))
            {
                contextEr = (ExtractResult)((Dictionary <string, object>)er.Data)[Constants.Context];
                if (contextEr.Type.Equals(Constants.ContextType_RelativeSuffix))
                {
                    dateTimeEr.Text = $"{er.Text} {contextEr.Text}";
                }
                else
                {
                    dateTimeEr.Text = $"{contextEr.Text} {er.Text}";
                }

                hasContext = true;
            }
            else
            {
                dateTimeEr.Text = er.Text;
            }

            var dateTimePr = new DateTimeParseResult();

            if (subType == Constants.SYS_DATETIME_DATE)
            {
                dateTimeEr.Type = Constants.SYS_DATETIME_DATE;
                dateTimePr      = this.config.DateParser.Parse(dateTimeEr, referenceTime);
            }
            else if (subType == Constants.SYS_DATETIME_TIME)
            {
                if (!hasContext)
                {
                    dateTimeEr.Type = Constants.SYS_DATETIME_TIME;
                    dateTimePr      = this.config.TimeParser.Parse(dateTimeEr, referenceTime);
                }
                else if (contextEr.Type == Constants.SYS_DATETIME_DATE || contextEr.Type == Constants.ContextType_RelativePrefix)
                {
                    // For cases:
                    //      Monday 9 am or 11 am
                    //      next 9 am or 11 am
                    dateTimeEr.Type = Constants.SYS_DATETIME_DATETIME;
                    dateTimePr      = this.config.DateTimeParser.Parse(dateTimeEr, referenceTime);
                }
                else if (contextEr.Type == Constants.ContextType_AmPm)
                {
                    // For cases: in the afternoon 3 o'clock or 5 o'clock
                    dateTimeEr.Type = Constants.SYS_DATETIME_TIME;
                    dateTimePr      = this.config.TimeParser.Parse(dateTimeEr, referenceTime);
                }
            }
            else if (subType == Constants.SYS_DATETIME_DATETIME)
            {
                // "next week Mon 9 am or Tue 1 pm"
                dateTimeEr.Type = Constants.SYS_DATETIME_DATETIME;
                dateTimePr      = this.config.DateTimeParser.Parse(dateTimeEr, referenceTime);
            }
            else if (subType == Constants.SYS_DATETIME_TIMEPERIOD)
            {
                if (!hasContext)
                {
                    dateTimeEr.Type = Constants.SYS_DATETIME_TIMEPERIOD;
                    dateTimePr      = this.config.TimePeriodParser.Parse(dateTimeEr, referenceTime);
                }
                else if (contextEr.Type == Constants.SYS_DATETIME_DATE || contextEr.Type == Constants.ContextType_RelativePrefix)
                {
                    dateTimeEr.Type = Constants.SYS_DATETIME_DATETIMEPERIOD;
                    dateTimePr      = this.config.DateTimePeriodParser.Parse(dateTimeEr, referenceTime);
                }
            }
            else if (subType == Constants.SYS_DATETIME_DATETIMEPERIOD)
            {
                if (!hasContext)
                {
                    dateTimeEr.Type = Constants.SYS_DATETIME_DATETIMEPERIOD;
                    dateTimePr      = this.config.DateTimePeriodParser.Parse(dateTimeEr, referenceTime);
                }
            }
            else if (subType == Constants.SYS_DATETIME_DATEPERIOD)
            {
                dateTimeEr.Type = Constants.SYS_DATETIME_DATEPERIOD;
                dateTimePr      = this.config.DatePeriodParser.Parse(dateTimeEr, referenceTime);
            }

            if (dateTimePr.Value != null)
            {
                ret.FutureValue = ((DateTimeResolutionResult)dateTimePr.Value).FutureValue;
                ret.PastValue   = ((DateTimeResolutionResult)dateTimePr.Value).PastValue;
                ret.Timex       = dateTimePr.TimexStr;

                // Create resolution
                GetResolution(er, dateTimePr, ret);

                ret.Success = true;
            }

            return(ret);
        }
コード例 #29
0
        public int GetYearFromText(Match match)
        {
            int year = Constants.InvalidYear;

            var yearStr = match.Groups["year"].Value;

            if (!string.IsNullOrEmpty(yearStr))
            {
                year = int.Parse(yearStr);
                if (year < 100 && year >= Constants.MinTwoDigitYearPastNum)
                {
                    year += 1900;
                }
                else if (year >= 0 && year < Constants.MaxTwoDigitYearFutureNum)
                {
                    year += 2000;
                }
            }
            else
            {
                var firstTwoYearNumStr = match.Groups["firsttwoyearnum"].Value;
                if (!string.IsNullOrEmpty(firstTwoYearNumStr))
                {
                    var er = new ExtractResult
                    {
                        Text   = firstTwoYearNumStr,
                        Start  = match.Groups["firsttwoyearnum"].Index,
                        Length = match.Groups["firsttwoyearnum"].Length
                    };

                    var firstTwoYearNum = Convert.ToInt32((double)(this.config.NumberParser.Parse(er).Value ?? 0));

                    var lastTwoYearNum    = 0;
                    var lastTwoYearNumStr = match.Groups["lasttwoyearnum"].Value;
                    if (!string.IsNullOrEmpty(lastTwoYearNumStr))
                    {
                        er.Text   = lastTwoYearNumStr;
                        er.Start  = match.Groups["lasttwoyearnum"].Index;
                        er.Length = match.Groups["lasttwoyearnum"].Length;

                        lastTwoYearNum = Convert.ToInt32((double)(this.config.NumberParser.Parse(er).Value ?? 0));
                    }

                    // Exclude pure number like "nineteen", "twenty four"
                    if (firstTwoYearNum < 100 && lastTwoYearNum == 0 || firstTwoYearNum < 100 && firstTwoYearNum % 10 == 0 && lastTwoYearNumStr.Trim().Split(' ').Length == 1)
                    {
                        year = Constants.InvalidYear;
                        return(year);
                    }

                    if (firstTwoYearNum >= 100)
                    {
                        year = firstTwoYearNum + lastTwoYearNum;
                    }
                    else
                    {
                        year = firstTwoYearNum * 100 + lastTwoYearNum;
                    }
                }
            }

            return(year);
        }
コード例 #30
0
        public static List <Token> ExtractorDurationWithBeforeAndAfter(string text, ExtractResult er, List <Token> ret,
                                                                       IDateTimeUtilityConfiguration utilityConfiguration)
        {
            var pos = (int)er.Start + (int)er.Length;

            if (pos <= text.Length)
            {
                var  afterString    = text.Substring(pos);
                var  beforeString   = text.Substring(0, (int)er.Start);
                var  isTimeDuration = utilityConfiguration.TimeUnitRegex.Match(er.Text).Success;
                int  index;
                bool isMatch         = false;
                var  agoLaterRegexes = new List <Regex>
                {
                    utilityConfiguration.AgoRegex,
                    utilityConfiguration.LaterRegex,
                };

                foreach (var regex in agoLaterRegexes)
                {
                    Token tokAfter = null, tokBefore = null;
                    bool  isDayMatch = false;

                    // Check afterString
                    if (MatchingUtil.GetAgoLaterIndex(afterString, regex, out index, inSuffix: true))
                    {
                        // We don't support cases like "5 minutes from today" for now
                        // Cases like "5 minutes ago" or "5 minutes from now" are supported
                        // Cases like "2 days before today" or "2 weeks from today" are also supported
                        isDayMatch = regex.Match(afterString).Groups["day"].Success;

                        if (!(isTimeDuration && isDayMatch))
                        {
                            tokAfter = new Token(er.Start ?? 0, (er.Start + er.Length ?? 0) + index);
                            isMatch  = true;
                        }
                    }

                    if (utilityConfiguration.CheckBothBeforeAfter)
                    {
                        // Check if regex match is split between beforeString and afterString
                        if (!isDayMatch && isMatch)
                        {
                            string beforeAfterStr = beforeString + afterString.Substring(0, index);
                            var    isRangeMatch   = utilityConfiguration.RangePrefixRegex.MatchBegin(afterString.Substring(index), trim: true).Success;
                            if (!isRangeMatch && MatchingUtil.GetAgoLaterIndex(beforeAfterStr, regex, out var indexStart, inSuffix: false))
                            {
                                isDayMatch = regex.Match(beforeAfterStr).Groups["day"].Success;

                                if (isDayMatch && !(isTimeDuration && isDayMatch))
                                {
                                    ret.Add(new Token(indexStart, (er.Start + er.Length ?? 0) + index));
                                    isMatch = true;
                                }
                            }
                        }

                        // Check also beforeString
                        if (MatchingUtil.GetAgoLaterIndex(beforeString, regex, out index, inSuffix: false))
                        {
                            isDayMatch = regex.Match(beforeString).Groups["day"].Success;
                            if (!(isTimeDuration && isDayMatch))
                            {
                                tokBefore = new Token(index, er.Start + er.Length ?? 0);
                                isMatch   = true;
                            }
                        }
                    }

                    if (tokAfter != null && tokBefore != null && tokBefore.Start + tokBefore.Length > tokAfter.Start)
                    {
                        // Merge overlapping tokens
                        ret.Add(new Token(tokBefore.Start, tokAfter.Start + tokAfter.Length - tokBefore.Start));
                    }
                    else if (tokAfter != null)
                    {
                        ret.Add(tokAfter);
                    }
                    else if (tokBefore != null)
                    {
                        ret.Add(tokBefore);
                    }

                    if (isMatch)
                    {
                        break;
                    }
                }

                if (!isMatch)
                {
                    // Item1 is the main regex to be tested
                    // Item2 is a list of unit regexes used to validate the extraction (in case of match, the extraction is discarded)
                    var inWithinRegexTuples = new List <(Regex, List <Regex>)>
                    {
                        (utilityConfiguration.InConnectorRegex, new List <Regex> {
                            utilityConfiguration.RangeUnitRegex
                        }),
                        (utilityConfiguration.WithinNextPrefixRegex, new List <Regex> {
                            utilityConfiguration.DateUnitRegex, utilityConfiguration.TimeUnitRegex
                        }),
                    };

                    foreach (var regex in inWithinRegexTuples)
                    {
                        bool isMatchAfter = false;
                        if (MatchingUtil.GetTermIndex(beforeString, regex.Item1, out index))
                        {
                            isMatch = true;
                        }
                        else if (utilityConfiguration.CheckBothBeforeAfter && MatchingUtil.GetAgoLaterIndex(afterString, regex.Item1, out index, inSuffix: true))
                        {
                            // Check also afterString
                            isMatch = isMatchAfter = true;
                        }

                        if (isMatch)
                        {
                            // For InConnectorRegex and range unit like "week, month, year", it should output dateRange or datetimeRange
                            // For WithinNextPrefixRegex and range unit like "week, month, year, day, second, minute, hour", it should output dateRange or datetimeRange
                            bool isUnitMatch = false;
                            foreach (var unitRegex in regex.Item2)
                            {
                                isUnitMatch = isUnitMatch || unitRegex.IsMatch(er.Text);
                            }

                            if (!isUnitMatch)
                            {
                                if (er.Start != null && er.Length != null && ((int)er.Start >= index || isMatchAfter))
                                {
                                    int start = (int)er.Start - (!isMatchAfter ? index : 0);
                                    int end   = (int)er.Start + (int)er.Length + (isMatchAfter ? index : 0);
                                    ret.Add(new Token(start, end));
                                }
                            }

                            break;
                        }
                    }
                }
            }

            return(ret);
        }