Esempio n. 1
0
        /// <summary>
        /// Given input string, we try to match beginning parts of the stirng with specified tag type
        /// Input content will be trimmed so caller need to be cautious if depends on number of charcters being consumed since return value won't contain it
        /// </summary>
        /// <param name="tagType">A string identifier of tag type</param>
        /// <param name="content">Non-bounded ending string</param>
        /// <param name="vocabulary"></param>
        /// <returns></returns>
        private string MatchTag(string tagType, string content, VocabularyManager vocabulary)
        {
            switch (tagType)
            {
            case "Email":
                // Extract non-phrase part
                string unknownString = vocabulary.GetUnknownPhrase(content);
                if (unknownString != null)
                {
                    try { MailAddress m = new MailAddress(unknownString); return(unknownString); }
                    catch (FormatException) { break; }
                }
                break;

            default:
                break;
            }
            return(null);
        }
Esempio 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);
        }