Exemple #1
0
        /// <summary>
        /// Scans a queue of runs and highlights matches.
        /// </summary>
        /// <param name="runQueue">Run queue</param>
        /// <param name="query">Query</param>
        /// <param name="addHighlightDelegate">Delegate to call when a hit is found</param>
        public virtual void ScanQueuedRuns(RunQueue runQueue, Query query, AddHighlight addHighlightDelegate)
        {
            //this.searchText = query;
            System.Text.StringBuilder queuedText = new System.Text.StringBuilder(100);
            queuedText.Length = 0;
            for (int i = 0; i < runQueue.Count && (i <= 1 || queuedText.Length < 100); i++)//look at the text in queue up until 100 chars of the 2nd run
            {
                queuedText.Append(runQueue[i].HitAvailableText);
            }
            int    currentIndex = 0;
            string text         = queuedText.ToString();
            int    index;
            Hit    hit;



            TextMatchers textMatchers = query.GetTextMatchers(text, FindOptions);

            while ((hit = GetNextMatch(textMatchers, currentIndex)).Start > -1 && currentGlobalScanHighlightCount < maximumHitsToHighlight)//find a hit for searchText in the plain text version.
            {
                index = hit.Start;
                //we have a hit, we need to find the runs it was in and highlight
                int highlightStart;
                int gobbledChars = 0;
                int runHitLength = hit.Length;
                int highlightLength;
                //string searchSegment = query.QueryText;
                bool moreToFind = true;
                while (moreToFind)
                {
                    Run runAtPos = runQueue.HitPosition(index, runHitLength, out highlightStart, out gobbledChars);

                    //gobbledChars is the number of chars in runAtPos that were used (this could be the entire run length if the runHitLength is less than the
                    //number of chars in the run).
                    //indexOffset is where in the run to start highlighting
                    if (gobbledChars < runHitLength)
                    {
                        moreToFind = true;
                        //there weren't enough chars in the run, so we'll need to look for more
                        index          += gobbledChars;
                        runHitLength   -= gobbledChars;
                        highlightLength = gobbledChars;
                    }
                    else
                    {
                        moreToFind      = false;
                        highlightLength = runHitLength;
                    }

                    addHighlightDelegate(runAtPos, highlightStart, highlightLength);
                    currentGlobalScanHighlightCount++;

                    currentIndex = index + runHitLength;
                }
            }
        }
Exemple #2
0
 internal void ResetMatchers()
 {
     //undo any changes to the query that ignore matchers made.
     queryString = originalQueryBeforeIgnoreHandlerChanges;
     if (textMatchers != null)
     {
         textMatchers.UnhookHandlers();
     }
     textMatchers = null;
 }
Exemple #3
0
        /// <summary>
        /// Gets the chosen text matchers for the query options.
        /// </summary>
        /// <param name="textToSearch">Text being searched.</param>
        /// <param name="findOptions">The chosen options.</param>
        /// <returns>Collection of matchers.</returns>
        public TextMatchers GetTextMatchers(string textToSearch, OptionsViewModel findOptions)
        {
            this.findOptions = findOptions;
            if (textMatchers == null)
            {
                textMatchers = CreateMatchers();
            }

            for (int i = 0; i < textMatchers.Count; i++)
            {
                textMatchers[i].SetText(textToSearch);
            }

            return(textMatchers);
        }
Exemple #4
0
        TextMatchers CreateMatchers()
        {
            int              currentIndex = 0;
            string           text         = "";
            StringComparison comparison;

            if (findOptions.MatchCase)
            {
                comparison = StringComparison.CurrentCulture;
            }
            else
            {
                comparison = StringComparison.CurrentCultureIgnoreCase;
            }



            //collection of match enumerators from the matchers.
            //List<IEnumerator<Hit>> matcherEnumerators = new List<IEnumerator<Hit>>(15);
            TextMatchers                   matchers            = new TextMatchers(15);
            List <IMatchFilter>            matchFilters        = new List <IMatchFilter>(5);
            List <IIgnoreCharacterHandler> bodyIgnoreHandlers  = new List <IIgnoreCharacterHandler>(2);
            List <IIgnoreCharacterHandler> queryIgnoreHandlers = new List <IIgnoreCharacterHandler>(2);

            //because wildcards and regexs will blow up our prefix/suffix/wholeword matchers, we have to treat them as filters instead.
            //---Filters
            if (findOptions.FindWholeWordsOnly)
            {
                matchFilters.Add(new WordPartFilter(WordPartFilter.Part.WholeWord));
            }

            if (findOptions.MatchPrefix)
            {
                matchFilters.Add(new WordPartFilter(WordPartFilter.Part.Prefix));
            }

            if (findOptions.MatchSuffix)
            {
                matchFilters.Add(new WordPartFilter(WordPartFilter.Part.Suffix));
            }

            //---Ignore handlers
            if (findOptions.IgnorePunctuationCharacters)
            {
                bodyIgnoreHandlers.Add(new IgnoreCharacterClassHandler(IgnoreCharacterClassHandler.CharacterClass.Punctuation));
                //translating the query is not compatible with wildcards or regex because both use punct. as special symbols
                if (!findOptions.UseRegularExpressions && !findOptions.UseWildcards)
                {
                    queryIgnoreHandlers.Add(new IgnoreCharacterClassHandler(IgnoreCharacterClassHandler.CharacterClass.Punctuation));
                }
            }

            if (findOptions.IgnoreWhitespaceCharacters)
            {
                bodyIgnoreHandlers.Add(new IgnoreCharacterClassHandler(IgnoreCharacterClassHandler.CharacterClass.Whitespace));
                queryIgnoreHandlers.Add(new IgnoreCharacterClassHandler(IgnoreCharacterClassHandler.CharacterClass.Whitespace));
            }



            //---Match Enumerators
            if (findOptions.UseRegularExpressions)
            {
                matchers.Add(new RegularExpressionTextMatcher(this, text, currentIndex, comparison, matchFilters, bodyIgnoreHandlers, queryIgnoreHandlers));
            }

            if (findOptions.UseWildcards)
            {
                matchers.Add(new WildcardTextMatcher(this, text, currentIndex, comparison, matchFilters, bodyIgnoreHandlers, queryIgnoreHandlers));
            }

            if (matchers.Count == 0) //add default
            {
                matchers.Add(new StandardTextMatcher(this, text, currentIndex, comparison, matchFilters, bodyIgnoreHandlers, queryIgnoreHandlers));
            }
            return(matchers);
        }
Exemple #5
0
        /// <summary>
        /// Returns the next match for <c>searchText</c> in <c>text</c> starting at <c>currentIndex</c>.
        /// </summary>
        /// <remarks>Some options are mutually exclusive (eg. find whole words only and match prefix), find whole words takes precedence.</remarks>
        /// <param name="currentIndex">Where to start looking from</param>
        /// <param name="matchers">Matchers to use in search for next hit.</param>
        /// <returns>Where current query occurs or -1 if it doesn't.</returns>
        protected virtual Hit GetNextMatch(TextMatchers matchers, int currentIndex)
        {
            List <IEnumerator <Hit> > matcherEnumerators = new List <IEnumerator <Hit> >(15);
            IEnumerator <Hit>         enumerator;
            bool allHaveMatches = true;

            //TextMatchers matchers = query.GetTextMatchers(FindOptions);
            for (int i = 0; i < matchers.Count; i++)
            {
                matchers[i].CurrentPosition = currentIndex;
                enumerator = matchers[i].GetEnumerator();
                matcherEnumerators.Add(enumerator);
                //init enumerator
                allHaveMatches &= enumerator.MoveNext();
            }



            //At this point, each matcher can be iterated over to give matches, eg.
            // matcher[0] => (has matches) [0, 5, 9]
            // matcher[1] => (has matches) [5]
            // matcher[2] => (has matches) [0, 3, 5, 9]

            //we want the AND, so, first 'round' gives
            //0, 5, 0 (for matchers 0,1 and 2)
            //for 1st round, find lowest matcher (0 or 2, so take 2), and advance it for next round.
            //2nd round gives
            //0, 5, 3
            //lowest is match 0, so advance it
            //3rd round gives
            //5,5,3
            //4th round
            //5,5,5 => hit, so return it.
            //otherwise if we never lined them all up, return -1.

            int  lowestMatcherValue = 0, lowestMatcher = 0;
            bool isHit = false;
            int  previousMatcherValue = -1;



            //loop through rounds, until find isHit (all match).
            while (allHaveMatches && !isHit)
            {
                isHit = true;
                //find the lowest matcher
                for (int i = 0; i < matcherEnumerators.Count; i++)
                {
                    if (matcherEnumerators[i].Current.Start <= lowestMatcherValue)
                    {
                        lowestMatcher      = i;
                        lowestMatcherValue = matcherEnumerators[i].Current.Start;
                    }
                    if (i > 0)
                    {
                        isHit &= matcherEnumerators[i].Current.Start == previousMatcherValue;
                    }

                    previousMatcherValue = matcherEnumerators[i].Current.Start;
                }

                if (!isHit)
                {
                    //move the lowest matcher forward
                    if (!matcherEnumerators[lowestMatcher].MoveNext())
                    {
                        break;
                    }
                }
                else
                {
                    return(matcherEnumerators[0].Current);//they're all the same, so return first
                }
            }

            return(new Hit(-1, 0));
        }
Exemple #6
0
        TextMatchers CreateMatchers()
        {
            int currentIndex = 0;
            string text = "";
            StringComparison comparison;
            if (findOptions.MatchCase) comparison = StringComparison.CurrentCulture;
            else comparison = StringComparison.CurrentCultureIgnoreCase;



            //collection of match enumerators from the matchers.
            //List<IEnumerator<Hit>> matcherEnumerators = new List<IEnumerator<Hit>>(15);
            TextMatchers matchers = new TextMatchers(15);
            List<IMatchFilter> matchFilters = new List<IMatchFilter>(5);
            List<IIgnoreCharacterHandler> bodyIgnoreHandlers = new List<IIgnoreCharacterHandler>(2);
            List<IIgnoreCharacterHandler> queryIgnoreHandlers = new List<IIgnoreCharacterHandler>(2);

            //because wildcards and regexs will blow up our prefix/suffix/wholeword matchers, we have to treat them as filters instead.  
            //---Filters
            if (findOptions.FindWholeWordsOnly)
                matchFilters.Add(new WordPartFilter(WordPartFilter.Part.WholeWord));

            if (findOptions.MatchPrefix)
                matchFilters.Add(new WordPartFilter(WordPartFilter.Part.Prefix));

            if (findOptions.MatchSuffix)
                matchFilters.Add(new WordPartFilter(WordPartFilter.Part.Suffix));

            //---Ignore handlers
            if (findOptions.IgnorePunctuationCharacters)
            {
                bodyIgnoreHandlers.Add(new IgnoreCharacterClassHandler(IgnoreCharacterClassHandler.CharacterClass.Punctuation));
                //translating the query is not compatible with wildcards or regex because both use punct. as special symbols
                if (!findOptions.UseRegularExpressions && !findOptions.UseWildcards)
                    queryIgnoreHandlers.Add(new IgnoreCharacterClassHandler(IgnoreCharacterClassHandler.CharacterClass.Punctuation));
            }

            if (findOptions.IgnoreWhitespaceCharacters)
            {
                bodyIgnoreHandlers.Add(new IgnoreCharacterClassHandler(IgnoreCharacterClassHandler.CharacterClass.Whitespace));
                queryIgnoreHandlers.Add(new IgnoreCharacterClassHandler(IgnoreCharacterClassHandler.CharacterClass.Whitespace));
            }



            //---Match Enumerators
            if (findOptions.UseRegularExpressions)
                matchers.Add(new RegularExpressionTextMatcher(this, text, currentIndex, comparison, matchFilters, bodyIgnoreHandlers, queryIgnoreHandlers));

            if (findOptions.UseWildcards)
                matchers.Add(new WildcardTextMatcher(this, text, currentIndex, comparison, matchFilters, bodyIgnoreHandlers, queryIgnoreHandlers));

            if (matchers.Count == 0) //add default
                matchers.Add(new StandardTextMatcher(this, text, currentIndex, comparison, matchFilters, bodyIgnoreHandlers, queryIgnoreHandlers));
            return matchers;
        }
Exemple #7
0
 internal void ResetMatchers()
 {
     //undo any changes to the query that ignore matchers made.
     queryString = originalQueryBeforeIgnoreHandlerChanges;
     if(textMatchers!=null)textMatchers.UnhookHandlers();
     textMatchers = null;
 }
Exemple #8
0
        /// <summary>
        /// Gets the chosen text matchers for the query options.
        /// </summary>
        /// <param name="textToSearch">Text being searched.</param>
        /// <param name="findOptions">The chosen options.</param>
        /// <returns>Collection of matchers.</returns>
        public TextMatchers GetTextMatchers(string textToSearch, OptionsViewModel findOptions)
        {
            this.findOptions = findOptions;
            if (textMatchers == null)
                textMatchers = CreateMatchers();

            for (int i = 0; i < textMatchers.Count; i++)
            {
                textMatchers[i].SetText(textToSearch);
            }

            return textMatchers;
        }
        /// <summary>
        /// Returns the next match for <c>searchText</c> in <c>text</c> starting at <c>currentIndex</c>.  
        /// </summary>
        /// <remarks>Some options are mutually exclusive (eg. find whole words only and match prefix), find whole words takes precedence.</remarks>
        /// <param name="currentIndex">Where to start looking from</param>
        /// <param name="matchers">Matchers to use in search for next hit.</param>
        /// <returns>Where current query occurs or -1 if it doesn't.</returns>
        protected virtual Hit GetNextMatch(TextMatchers matchers, int currentIndex)
        {
            List<IEnumerator<Hit>> matcherEnumerators = new List<IEnumerator<Hit>>(15);
            IEnumerator<Hit> enumerator;
            bool allHaveMatches = true;
            //TextMatchers matchers = query.GetTextMatchers(FindOptions);
            for (int i = 0; i < matchers.Count; i++)
            {
                matchers[i].CurrentPosition = currentIndex;
                enumerator = matchers[i].GetEnumerator();
                matcherEnumerators.Add(enumerator);
                //init enumerator
                allHaveMatches &= enumerator.MoveNext();
            }

            

            //At this point, each matcher can be iterated over to give matches, eg.
            // matcher[0] => (has matches) [0, 5, 9]
            // matcher[1] => (has matches) [5]
            // matcher[2] => (has matches) [0, 3, 5, 9]

            //we want the AND, so, first 'round' gives
            //0, 5, 0 (for matchers 0,1 and 2)
            //for 1st round, find lowest matcher (0 or 2, so take 2), and advance it for next round.
            //2nd round gives
            //0, 5, 3
            //lowest is match 0, so advance it
            //3rd round gives
            //5,5,3
            //4th round
            //5,5,5 => hit, so return it.
            //otherwise if we never lined them all up, return -1.

            int lowestMatcherValue=0, lowestMatcher=0;
            bool isHit = false;
            int previousMatcherValue=-1;

            
            
    

            //loop through rounds, until find isHit (all match).
            while (allHaveMatches && !isHit)
            {
                isHit = true;
                //find the lowest matcher
                for (int i = 0; i < matcherEnumerators.Count; i++)
                {
                    if (matcherEnumerators[i].Current.Start <= lowestMatcherValue)
                    {
                        lowestMatcher = i;
                        lowestMatcherValue = matcherEnumerators[i].Current.Start;
                    }
                    if (i > 0) isHit &= matcherEnumerators[i].Current.Start == previousMatcherValue;

                    previousMatcherValue = matcherEnumerators[i].Current.Start;
                }

                if (!isHit)
                {
                    //move the lowest matcher forward
                    if (!matcherEnumerators[lowestMatcher].MoveNext())
                    {
                        break;
                    }
                }
                else return matcherEnumerators[0].Current;//they're all the same, so return first
            }

            return new Hit(-1,0);
            
            


        }