Ejemplo n.º 1
0
        /// <summary>
        /// Check whether beginning parts of input string matches a cateogry, return the matched part
        /// </summary>
        /// <param name="category">category to match</param>
        /// <param name="bInclusive"></param>
        /// <param name="content"></param>
        /// <param name="vocabulary"></param>
        /// <returns>null if not found</returns>
        private string MatchCategory(string category, bool bInclusive, string content, VocabularyManager vocabulary)
        {
            // Might want to use a GetPhrase() first
            Phrase phrase = vocabulary.GetPhrase(content);

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

            // Then check whether or not the phrase is in the category
            if (bInclusive)
            {
                if (vocabulary.IsInCategory(category, phrase))
                {
                    return(phrase.Key);
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                if (vocabulary.IsNotInCategory(category, phrase))
                {
                    return(phrase.Key);
                }
                else
                {
                    return(null);
                }
            }
        }
Ejemplo n.º 2
0
        // Match Functions
        /// <summary>
        /// Match input sentence with current element and output relavent parts, by nature of design elements only match as long as it can recognize and doesn't require input sentence to be exact length
        /// bOptional should be checked by caller
        /// </summary>
        /// <param name="content">string to be matched from begining</param>
        /// <param name="consumed">actual number of characters consumed during the match</param>
        /// <returns>An element instance if match found, otherwise null; Caller might also want to remove trailing space</returns>
        /// <Debug> By design MatchELement doesn't consider English spacing, so caller must be cautious about that since consumed doesn't count ending spaces</Debug>
        public PatternElementInstance MatchElement(string content, VocabularyManager vocabulary, out int consumed)
        {
            switch (Type)
            {
            case PatternElementType.SpecificWord:
                consumed = content.IndexOf(content.TrimStart());
                if (content.TrimStart().IndexOf(Key.ToLower()) == 0)
                {
                    consumed += Key.Length;
                    return(new PatternElementInstance(Type, Key));
                }
                break;

            case PatternElementType.VarietyWord:
                consumed = content.IndexOf(content.TrimStart());
                if (vocabulary.IsPraseVaryingFormOrSynonymUndetermined(content.TrimStart(), Key, ref consumed) == true)
                {
                    return(new PatternElementInstance(Type, content.Substring(0, consumed)));
                }
                break;

            case PatternElementType.WordAttribute:
                // We do not explicitly trim for this; Handling of beginning white spaces dealt with below
                if (Key == "any")
                {
                    throw new Exception("Any should be handled outside");
                }
                else
                {
                    // Get attribtues to match; Attributes are guaranted to be valid at load time
                    bool          bInfinite  = (Key.ElementAt(0) == '*');
                    string[]      attributes = Key.Split(new char[] { '+', '*' });
                    WordAttribute attribute  = 0;
                    foreach (string a in attributes)
                    {
                        if (string.IsNullOrWhiteSpace(a))
                        {
                            continue;
                        }
                        attribute |= (WordAttribute)Enum.Parse(typeof(WordAttribute), a);
                    }
                    consumed = 0;
                    // The input must be recognziable so it's gonna be a phrase of some kind
                    Phrase phrase = vocabulary.GetPhrase(content);     // <Improvement> Could we be matching the shortest attribute? // <Warning> GetPhrase() trimmed, so phrase.Length might not equal actual consumed characters
                    while (phrase != null)
                    {
                        // Try match against attributes
                        if ((phrase.Attribute & attribute) == attribute || attribute == WordAttribute.any)
                        {
                            consumed += content.IndexOf(phrase.Key) + phrase.Key.Length;    // Use content.IndexOf(phrase.Key) first to find where in the original string our phrase is is necessary for sometimes there might be some spaces in front of it
                            phrase    = vocabulary.GetPhrase(content.Substring(consumed));  // Continue with next phrase
                        }
                        else
                        {
                            phrase = null;
                        }
                        if (!bInfinite)
                        {
                            break;
                        }
                    }
                    if (consumed != 0)
                    {
                        return(new PatternElementInstance(Type, content.Substring(0, consumed).Trim()));       // Return that many elements as one single phrase (which by itself may not exist in the library)
                        // <Development> This can be utilzied by action handlers for learning new expressions e.g. "big shinny red juicy" apple
                    }
                }
                break;

            case PatternElementType.SubPattern:
                consumed = 0;
                PatternInstance subPatternInstance = SubPattern.Match(content, vocabulary, ref consumed, false);
                if (subPatternInstance != null)
                {
                    return(new PatternElementInstance(Type, subPatternInstance));
                }
                break;

            case PatternElementType.Choice:
                // Emitting a successful choice at the first matching // <Improvement> A more accurate way would be to match all options and use the longest match, e.g. Courtesy Interrupt
                PatternElementInstance ChoiceInstance = null;
                foreach (PatternElement choiceElement in Choices)
                {
                    ChoiceInstance = choiceElement.MatchElement(content, vocabulary, out consumed);
                    if (ChoiceInstance != null)
                    {
                        return(new PatternElementInstance(Type, ChoiceInstance.ElementValue));
                    }
                }
                // Valid if we have at least one and only one choice
                break;

            case PatternElementType.Tag:
                consumed = content.IndexOf(content.TrimStart());
                string tagValue = MatchTag(Key, content.TrimStart(), vocabulary);
                if (tagValue != null)
                {
                    consumed += tagValue.Length;
                    return(new PatternElementInstance(Type, tagValue));
                }
                break;

            case PatternElementType.CategoryInclude:
            {
                consumed = content.IndexOf(content.TrimStart());
                string match = MatchCategory(Key, true, content.TrimStart(), vocabulary);
                if (match != null)
                {
                    consumed += match.Length;
                    return(new PatternElementInstance(Type, match));
                }
            }
            break;

            case PatternElementType.CategoryExclude:
            {
                consumed = content.IndexOf(content.TrimStart());
                string match = MatchCategory(Key, false, content.TrimStart(), vocabulary);
                if (match != null)
                {
                    consumed += match.Length;
                    return(new PatternElementInstance(Type, match));
                }
            }
            break;

            case PatternElementType.Punctuation:
                if (content.IndexOf(Key) == 0)
                {
                    consumed = Key.Length;
                    return(new PatternElementInstance(Type, Key));
                }
                break;

            case PatternElementType.UnknownPhrase:
                // Try extract unknown from known
                string unknownString = vocabulary.GetUnknownPhrase(content);
                if (unknownString != null)      // Commit only if we find no match
                {
                    consumed = unknownString.Length;
                    return(new PatternElementInstance(Type, unknownString));
                }
                break;

            default:
                break;
            }
            consumed = 0;
            return(null);
        }