private void buttonReplaceAll_Click(object sender, EventArgs e) { foreach (var result in _resultMap) { FinderHelpers.ReplaceText(result.Value, tbSearchKey.Text, tbReplaceKey.Text); } }
private void buttonReplace_Click(object sender, EventArgs e) { var key = int.Parse(listResults.SelectedItems[0].SubItems[0].Text); Microsoft.Office.Interop.Word.Range selRng = listResults.SelectedItems.Count != 0 ? _resultMap[key] : null; if (selRng != null) { FinderHelpers.ReplaceText(selRng, tbSearchKey.Text, tbReplaceKey.Text); } }
/// <summary> /// DoFind is the helper for a regular Find (no proximity). Very simple logic: /// Given a Regex Match, it will iterate through the match adding matches to /// the OberservableConcurrentDictionary /// </summary> /// <param name="match">The regex match based on the Find box text value</param> /// <param name="startRange">The Paragraph's start range - we need this for highlighting</param> /// <param name="endRange">The Paragraph's end range - we need this for highlighting</param> /// <param name="observableResults">The concurrent dictionary we are writing results to</param> public static void DoFind(SysRegex.Match match, int startRange, int endRange, OCDictionary observableResults) { while (match.Success) { // get actual match start and end range locations var beginRangeMatch = startRange + match.Index; var endRangeMatch = beginRangeMatch + match.Length; // get some context for the match var beginContext = beginRangeMatch >= 5 ? (beginRangeMatch - 5) : beginRangeMatch; var endContext = (endRangeMatch + 5) < endRange ? (endRangeMatch + 5) : endRange; FinderHelpers.AddResults(beginRangeMatch, endRangeMatch, beginContext, endContext, observableResults); match = match.NextMatch(); } }
public static Task FindText(string searchKey, bool searchKeyCaseSensitive, ObservableConcurrentDictionary <Word.Range, string> observableResults, IProgress <int> progress, CancellationToken cancelToken, ProxSearchSettings prox = null) { return(Task.Run(() => { var paraVisitedCount = 0; var proxIsNull = (prox == null); int totalParaCount = DocumentHelpers.ActiveDocument.Paragraphs.Count; var pOpts = new ParallelOptions { CancellationToken = cancelToken }; var sKeyRegOpts = searchKeyCaseSensitive ? SysRegex.RegexOptions.None : SysRegex.RegexOptions.IgnoreCase; var searchKeyRegex = proxIsNull ? new SysRegex.Regex(searchKey, sKeyRegOpts) : new SysRegex.Regex(searchKey + ".*?" + prox.SearchKey + "|" + prox.SearchKey + ".*?" + searchKey + "|" + searchKey, sKeyRegOpts); Parallel.ForEach(DocumentHelpers.GetParagraphsEnumerator(), pOpts, (currentParagraph, loopState, index) => { // Catch this cancellation throw in the FindPane to update the pane/results pOpts.CancellationToken.ThrowIfCancellationRequested(); var paraRange = ((Word.Paragraph)currentParagraph).Range; // Find all of the single Find matches if (proxIsNull) { FinderHelpers.DoFind(searchKeyRegex.Match(paraRange.Text), paraRange.Start, paraRange.End, observableResults); } #region Proximity Matching // Proximity matching else { // If we are doing interparagraph matching, let's make sure we don't // try to access a paragraph out of bounds if (prox.ParaProximity) { int lookaheadPosition = (int)index + prox.ParaThreshold; int topRange = (lookaheadPosition > totalParaCount) ? totalParaCount : lookaheadPosition; //Debug.WriteLine("LAP: " + lookaheadPosition.ToString() + // "Total: " + totalParaCount.ToString() + // "topRng: " + topRange.ToString()); paraRange.End = prox.ParaEndingRanges[topRange - 1]; } IEnumerable <SysRegex.Match> matches = null; if (paraRange.Text != null) { if (!prox.LogicalNot) { searchKeyRegex = new SysRegex.Regex(searchKey + ".*?" + prox.SearchKey, sKeyRegOpts); var proxKeyRegex = new SysRegex.Regex(prox.SearchKey + ".*?" + searchKey, sKeyRegOpts); var skMatches = searchKeyRegex.Matches(paraRange.Text); var pkMatches = proxKeyRegex.Matches(paraRange.Text); matches = skMatches.OfType <SysRegex.Match>() .Concat(pkMatches.OfType <SysRegex.Match>()) .Where(m => m.Success); } else { // why didn't we do this in the assignment of matches and let the if statement // override its value? imagine all of the wasted ops this call does // if its not needed! matches = searchKeyRegex.Matches(paraRange.Text).OfType <SysRegex.Match>(); } FinderHelpers.DoFindProximity(matches, paraRange.Start, paraRange.End, new SysRegex.Regex(searchKey, sKeyRegOpts), prox, observableResults); } } #endregion Proximity Matching // Report back our progress progress.Report(++paraVisitedCount); }); }, cancelToken)); }
/// <summary> /// DoFindProximity takes matches and decides if they are truly proximity based on /// 1. Stripping the match of special characters and extra whitespace /// 2. Splitting the match into a list based on whitespace /// Once we have a list, we can just walk through the X proximity words to see if a match /// exists. This means you can't search for a word within X words of a hyphen. /// </summary> /// <param name="matches">Enumberable list of possible matches</param> /// <param name="startRange">The Paragraph's start range - we need this for highlighting</param> /// <param name="endRange">The Paragraph's end range - we need this for highlighting</param> /// <param name="searchKeyRegex">SearchKey</param> /// <param name="prox">Prox object, to tell us ProxRegKey, proximity, case sensitive, etc</param> /// <param name="observableResults">The concurrent dictionary we are writing results to</param> public static void DoFindProximity(IEnumerable <SysRegex.Match> matches, int startRange, int endRange, SysRegex.Regex searchKeyRegex, ProxSearchSettings prox, OCDictionary observableResults) { foreach (var match in matches) { // so if our searchKey is "this " and the proxKey is "search", we will match the following with threshold = 5 // 1. this sentence represents a search string that has a hit // Match: this.*search // 2. search string in this sentence // Match: search.*this // first lets find our search key var searchKeyMatch = searchKeyRegex.Match(match.Value); while (searchKeyMatch.Success) { var pKeyRegOpts = prox.CaseSensitive ? SysRegex.RegexOptions.None : SysRegex.RegexOptions.IgnoreCase; var proximityKeyRegex = new SysRegex.Regex(prox.SearchKey, pKeyRegOpts); var searchKeyMatchEndpoint = searchKeyMatch.Index + searchKeyMatch.Length; // so if our searchKey is "this " and the proxKey is "search", with a threshold = 5 // // 1. this sentence represents a search string that has a hit // | || | | | // \ / \ \ / / // searchKey \ proxKey / // \________afterWords__________/ // // 2. search string in this sentence // || | || || | // | \ / | \ / | | // | proxKey |searchKey | // \ / \ / // \_beforeWords_/ afterWords string beforeWords = FinderHelpers.GetProximityWords(match.Value.Substring(0, searchKeyMatch.Index), prox.WordThreshold, true); string afterWords = FinderHelpers.GetProximityWords(match.Value.Substring(searchKeyMatchEndpoint), prox.WordThreshold, false); var beforeMatch = proximityKeyRegex.Match(beforeWords); var afterMatch = proximityKeyRegex.Match(afterWords); var successPredicate = prox.LogicalNot ? (!beforeMatch.Success && !afterMatch.Success) : (beforeMatch.Success || afterMatch.Success); while (successPredicate) { // Find where the match starts - before or after search key int matchIndex = beforeMatch.Success ? ((beforeWords.Length - beforeMatch.Index + 2) * -1) : afterMatch.Success ? afterMatch.Index + afterMatch.Length + 3 : 0; int searchKeyIndex = startRange + match.Index + searchKeyMatch.Index; int proxKeyIndex = searchKeyIndex + matchIndex; int startIndex = searchKeyIndex < proxKeyIndex ? searchKeyIndex : proxKeyIndex; int endIndex = searchKeyIndex > proxKeyIndex ? searchKeyIndex : proxKeyIndex; FinderHelpers.AddResults(startIndex, endIndex + searchKeyMatch.Length, observableResults); // So, if we are searching IN proximity, then let's get all matches IN proximity // both the before matches, AND the after matches if (!prox.LogicalNot) { beforeMatch = beforeMatch.NextMatch(); afterMatch = afterMatch.NextMatch(); successPredicate = (beforeMatch.Success || afterMatch.Success); } // Otherwise, we found a match that is NOT in proximity (before/after) of the search word, // so let's take it and break out of the loop (no need to search further...) else { break; } } searchKeyMatch = searchKeyMatch.NextMatch(); } } }