/// ------------------------------------------------------------------------------------ /// <summary> /// Cleans up the given source-language phrase (makes it all lowercase and removes /// punctuation and extraneous whitespace) and returns a collection of phrase parts, /// broken up by key terms. /// </summary> /// <returns>Collection of phrase parts</returns> /// ------------------------------------------------------------------------------------ internal IEnumerable <IPhrasePart> Parse() { KeyTermMatch bestKeyTerm = null; int minUnhandled = 0; for (m_iStartMatch = m_iNextWord = 0; m_iNextWord < m_words.Count;) { bestKeyTerm = FindBestKeyTerm(); if (bestKeyTerm == null) { m_iNextWord++; } else { // We've found the best key term we're going to find. int keyTermWordCount = bestKeyTerm.Words.Count(); if (m_iStartMatch > minUnhandled) { yield return(YieldPart(m_words.Skip(minUnhandled).Take(m_iStartMatch - minUnhandled), m_phrase, 0)); } yield return(bestKeyTerm); m_iStartMatch = m_iNextWord = minUnhandled = m_iStartMatch + keyTermWordCount; } } if (minUnhandled < m_words.Count) { yield return(YieldPart(m_words.Skip(minUnhandled), m_phrase, 0)); } }
public void CanRenderingBeDeleted_NonExistentRendering() { IKeyTerm ktFun = KeyTermMatchBuilderTests.AddMockedKeyTerm("having a blast"); ktFun.Stub(kt => kt.Renderings).Return(new[] { "abc" }); KeyTermMatchBuilder bldr = new KeyTermMatchBuilder(ktFun); KeyTermMatch matchFun = bldr.Matches.First(); Assert.IsFalse(matchFun.CanRenderingBeDeleted("xyz")); }
public void AddRenderingFailsToAddDuplicate() { IKeyTerm ktFun = KeyTermMatchBuilderTests.AddMockedKeyTerm("good times"); ktFun.Stub(kt => kt.Renderings).Return(new[] { "abc", "xyz" }); KeyTermMatchBuilder bldr = new KeyTermMatchBuilder(ktFun); KeyTermMatch matchFun = bldr.Matches.First(); Assert.Throws(typeof(ArgumentException), () => matchFun.AddRendering("abc")); }
public void GetNormalRenderings() { IKeyTerm ktFun = KeyTermMatchBuilderTests.AddMockedKeyTerm("diversion"); ktFun.Stub(kt => kt.Renderings).Return(new [] { "abc", "xyz" }); KeyTermMatchBuilder bldr = new KeyTermMatchBuilder(ktFun); KeyTermMatch matchFun = bldr.Matches.First(); Assert.IsTrue(matchFun.Renderings.SequenceEqual(ktFun.Renderings)); }
public void CanRenderingBeDeleted_DefaultRendering() { IKeyTerm ktFun = KeyTermMatchBuilderTests.AddMockedKeyTerm("time of my life"); ktFun.Stub(kt => kt.Renderings).Return(new[] { "abc" }); KeyTermMatchBuilder bldr = new KeyTermMatchBuilder(ktFun); KeyTermMatch matchFun = bldr.Matches.First(); matchFun.AddRendering("bestest"); matchFun.BestRendering = "bestest"; Assert.IsFalse(matchFun.CanRenderingBeDeleted("bestest")); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Determines whether the part of the phrase we're considering matches the key term so /// far. /// </summary> /// ------------------------------------------------------------------------------------ private bool PhraseEqualsKeyTermSoFar(KeyTermMatch term, int cMatchingWordsInTermSoFar) { int cCompare = Math.Min(term.m_words.Count, cMatchingWordsInTermSoFar); for (int iWord = m_iStartMatch; iWord < cCompare + m_iStartMatch; iWord++) { if (!term.m_words[iWord - m_iStartMatch].IsEquivalent(m_words[iWord])) { return(false); } } return(true); }
public void AddAndRemoveRenderings() { IKeyTerm ktFun = KeyTermMatchBuilderTests.AddMockedKeyTerm("fun"); ktFun.Stub(kt => kt.Renderings).Return(new [] { "abc", "xyz" }); KeyTermMatchBuilder bldr = new KeyTermMatchBuilder(ktFun); KeyTermMatch matchFun = bldr.Matches.First(); matchFun.AddRendering("wunkyboo"); Assert.AreEqual(3, matchFun.Renderings.Count()); Assert.IsTrue(matchFun.Renderings.Contains("wunkyboo")); Assert.IsTrue(matchFun.CanRenderingBeDeleted("wunkyboo")); Assert.IsFalse(matchFun.CanRenderingBeDeleted("abc")); matchFun.DeleteRendering("wunkyboo"); Assert.IsFalse(matchFun.Renderings.Contains("wunkyboo")); }
public void RuleToLimitMatchToTermRefs() { Dictionary <string, KeyTermRule> rules = new Dictionary <string, KeyTermRule>(); KeyTermRule rule = new KeyTermRule(); rule.id = "ask"; rule.Rule = KeyTermRule.RuleType.MatchForRefOnly; rules[rule.id] = rule; KeyTermMatchBuilder bldr = new KeyTermMatchBuilder(AddMockedKeyTerm(rule.id, 34), rules); Assert.AreEqual(1, bldr.Matches.Count()); KeyTermMatch ktm = VerifyKeyTermMatch(bldr, 0, false, "ask"); Assert.IsFalse(ktm.AppliesTo(30, 33)); Assert.IsTrue(ktm.AppliesTo(34, 34)); Assert.IsFalse(ktm.AppliesTo(35, 39)); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Verifies the key term match. /// </summary> /// ------------------------------------------------------------------------------------ private static KeyTermMatch VerifyKeyTermMatch(KeyTermMatchBuilder bldr, int iMatch, bool matchAnywhere, params string[] words) { KeyTermMatch ktm = bldr.Matches.ElementAt(iMatch); Assert.AreEqual(words.Length, ktm.Words.Count()); for (int i = 0; i < words.Length; i++) { Assert.AreEqual(words[i], ktm.Words.ElementAt(i).Text); } if (matchAnywhere) { Random r = new Random(DateTime.Now.Millisecond); Assert.IsTrue(ktm.AppliesTo(r.Next(), r.Next())); } return(ktm); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Initializes a new instance of the <see cref="T:TermRenderingCtrl"/> class. /// </summary> /// ------------------------------------------------------------------------------------ public TermRenderingCtrl(KeyTermMatch term, int endOffsetOfPrev, Action<bool> selectKeyboard, Action<IEnumerable<IKeyTerm>> lookupTerm) { InitializeComponent(); DoubleBuffered = true; m_term = term; m_selectKeyboard = selectKeyboard; m_lookupTerm = lookupTerm; m_lblKeyTermColHead.Text = term.Term; EndOffsetOfRenderingOfPreviousOccurrenceOfThisTerm = endOffsetOfPrev; m_lbRenderings.Items.AddRange(term.Renderings.Distinct().ToArray()); term.BestRenderingChanged += term_BestRenderingChanged; mnuLookUpTermC.Text = string.Format(mnuLookUpTermC.Text, s_AppName); mnuLookUpTermH.Text = string.Format(mnuLookUpTermC.Text, s_AppName); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Initializes a new instance of the <see cref="T:TermRenderingCtrl"/> class. /// </summary> /// ------------------------------------------------------------------------------------ public TermRenderingCtrl(KeyTermMatch term, int endOffsetOfPrev, Action <bool> selectKeyboard, Action <IEnumerable <IKeyTerm> > lookupTerm) { InitializeComponent(); DoubleBuffered = true; m_term = term; m_selectKeyboard = selectKeyboard; m_lookupTerm = lookupTerm; m_lblKeyTermColHead.Text = term.Term; EndOffsetOfRenderingOfPreviousOccurrenceOfThisTerm = endOffsetOfPrev; m_lbRenderings.Items.AddRange(term.Renderings.Distinct().ToArray()); term.BestRenderingChanged += term_BestRenderingChanged; mnuLookUpTermC.Text = string.Format(mnuLookUpTermC.Text, s_AppName); mnuLookUpTermH.Text = string.Format(mnuLookUpTermC.Text, s_AppName); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Populates the key terms table. /// </summary> /// ------------------------------------------------------------------------------------ private void PopulateKeyTermsTable(IEnumerable <IKeyTerm> keyTerms, KeyTermRules rules) { Dictionary <string, KeyTermRule> ktRules = new Dictionary <string, KeyTermRule>(); if (rules != null) { foreach (KeyTermRule keyTermRule in rules.Items.Where(keyTermRule => !String.IsNullOrEmpty(keyTermRule.id))) { ktRules[keyTermRule.id] = keyTermRule; } } KeyTermMatchBuilder matchBuilder; foreach (IKeyTerm keyTerm in keyTerms) { matchBuilder = new KeyTermMatchBuilder(keyTerm, ktRules); foreach (KeyTermMatch matcher in matchBuilder.Matches) { if (!matcher.Words.Any()) { continue; } List <KeyTermMatch> foundMatchers; Word firstWord = matcher.Words.First(); if (!m_keyTermsTable.TryGetValue(firstWord, out foundMatchers)) { m_keyTermsTable[firstWord] = foundMatchers = new List <KeyTermMatch>(); } KeyTermMatch existingMatcher = foundMatchers.FirstOrDefault(m => m.Equals(matcher)); if (existingMatcher == null) { foundMatchers.Add(matcher); } else { existingMatcher.AddTerm(keyTerm); } } } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Finds the best key term in the list of words starting at m_iStartMatch and including /// up to m_iNextWord. As new words are considered, the list possible matches /// (m_matches) is reduced by any that no longer match until there is exactly one match /// that exactly equals the words in the key term or the list is empty. /// </summary> /// ------------------------------------------------------------------------------------ private KeyTermMatch FindBestKeyTerm() { Word nextWord = m_words[m_iNextWord]; if (m_iStartMatch == m_iNextWord) { List <KeyTermMatch> matches; if (!m_keyTermsTable.TryGetValue(nextWord, out matches)) { Word stem = s_stemmer.stemTerm(nextWord); if (m_keyTermsTable.TryGetValue(stem, out matches)) { stem.AddAlternateForm(nextWord); } else { m_iStartMatch++; return(null); } } m_matches = new List <KeyTermMatch>(matches.Where(m => m.AppliesTo(m_phrase.StartRef, m_phrase.EndRef))); // If we found a one-word exact match and there are no other key terms that start // with that word, then we return it. The code below would handle this, but it's such // a common case, we want it to be fast. If there are one or more multi-word key // terms that start with this word, we need to keep looking. if (m_matches.Count == 1 && m_matches[0].Words.Count() == 1) { return(m_matches[0]); } } int cMatchingWordsInTermSoFar = m_iNextWord - m_iStartMatch + 1; int lengthOfBestMatch = 0; KeyTermMatch longestMatch = null; // Remove from the possible matches any that don't match so far for (int iTerm = 0; iTerm < m_matches.Count; iTerm++) { KeyTermMatch term = m_matches[iTerm]; if (!PhraseEqualsKeyTermSoFar(term, cMatchingWordsInTermSoFar) || (AtEndOfPhrase && term.m_words.Count > cMatchingWordsInTermSoFar)) { m_matches.RemoveAt(iTerm--); } else if (term.m_words.Count > lengthOfBestMatch) { lengthOfBestMatch = term.m_words.Count; longestMatch = term; } } if (m_matches.Count == 0) { // The only matches we had were multi-word matches, and the addition of the current // word made it so that none of them matched. Therefore, we don't have a key term // starting at iStartMatch. m_iNextWord = m_iStartMatch; // The for loop in Parse will increment this. m_iStartMatch++; return(null); } if ((m_matches.Count == 1 && lengthOfBestMatch < cMatchingWordsInTermSoFar) || (lengthOfBestMatch == cMatchingWordsInTermSoFar)) { return(longestMatch); } return(null); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Handles a change (probably from another TermRenderingCtrl) to our term's best /// rendering. /// </summary> /// ------------------------------------------------------------------------------------ void term_BestRenderingChanged(KeyTermMatch sender) { m_lbRenderings.Invalidate(); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Determines whether the part of the phrase we're considering matches the key term so /// far. /// </summary> /// ------------------------------------------------------------------------------------ private bool PhraseEqualsKeyTermSoFar(KeyTermMatch term, int cMatchingWordsInTermSoFar) { int cCompare = Math.Min(term.m_words.Count, cMatchingWordsInTermSoFar); for (int iWord = m_iStartMatch; iWord < cCompare + m_iStartMatch; iWord++) { if (!term.m_words[iWord - m_iStartMatch].IsEquivalent(m_words[iWord])) return false; } return true; }