/// <summary> /// Initializes a new instance of the Grep class. /// </summary> /// <history> /// [Curtis_Beard] 07/12/2006 Created /// [Andrew_Radford] 13/08/2009 Added Const. dependency on ISearchSpec, IFileFilterSpec /// [Curtis_Beard] 05/28/2015 FIX: 69, Created for speed improvements for encoding detection /// </history> public Grep(ISearchSpec searchSpec, IFileFilterSpec filterSpec) { if (searchSpec.EncodingDetectionOptions == null) { throw new ArgumentNullException("ISearchSpec.EncodingDetectionOptions", "EncodingDetectionOptions must not be null"); } SearchSpec = searchSpec; FileFilterSpec = filterSpec; MatchResults = new List<MatchResult>(); if (FileFilterSpec.FilterItems != null) { // get first file->minimum hit count filter (should only be 1) var fileCountFilter = (from f in FileFilterSpec.FilterItems where f.FilterType.Category == FilterType.Categories.File && f.FilterType.SubCategory == FilterType.SubCategories.MinimumHitCount select f).FirstOrDefault(); if (fileCountFilter != null) { int.TryParse(fileCountFilter.Value, out userFilterCount); } } if (SearchSpec.EncodingDetectionOptions.DetectFileEncoding && SearchSpec.EncodingDetectionOptions.UseEncodingCache) { EncodingCache.Instance.Load(SearchSpec.EncodingDetectionOptions.PerformanceSetting); } }
/// <summary> /// Searches the given file for the given search text. /// </summary> /// <param name="file">FileInfo object</param> /// <param name="searchSpec">ISearchSpec interface value</param> /// <param name="ex">Exception holder if error occurs</param> /// <returns>Hitobject containing grep results, null if on error</returns> public MatchResult Grep(FileInfo file, ISearchSpec searchSpec, ref Exception ex) { // initialize Exception object to null ex = null; MatchResult match = null; if (Parser.IsParseable(file.FullName)) { string fileContent = Parser.Parse(file.FullName); if (!string.IsNullOrEmpty(fileContent)) { string[] lines = fileContent.Split(new char[] { '\n', '\r' }); for (int i = 0; i < lines.Length; i++) { string line = lines[i]; int posInStr = -1; Regex reg = null; MatchCollection regCol = null; if (searchSpec.UseRegularExpressions) { string pattern = string.Format("{0}{1}{0}", searchSpec.UseWholeWordMatching ? "\\b" : string.Empty, searchSpec.SearchText); RegexOptions options = searchSpec.UseCaseSensitivity ? RegexOptions.None : RegexOptions.IgnoreCase; reg = new Regex(pattern, options); regCol = reg.Matches(line); if (regCol.Count > 0) { posInStr = 1; } } else { // If we are looking for whole worlds only, perform the check. if (searchSpec.UseWholeWordMatching) { reg = new Regex("\\b" + Regex.Escape(searchSpec.SearchText) + "\\b", searchSpec.UseCaseSensitivity ? RegexOptions.None : RegexOptions.IgnoreCase); // if match is found, also check against our internal line hit count method to be sure they are in sync Match mtc = reg.Match(line); if (mtc != null && mtc.Success && libbSearch.Grep.RetrieveLineMatches(line, searchSpec).Count > 0) { posInStr = mtc.Index; } } else { posInStr = line.IndexOf(searchSpec.SearchText, searchSpec.UseCaseSensitivity ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); } } if (posInStr > -1) { if (match == null) { match = new MatchResult(file); // found hit in file so just return if (searchSpec.ReturnOnlyFileNames) { break; } } var matchLineFound = new MatchResultLine() { Line = line, LineNumber = -1, HasMatch = true }; if (searchSpec.UseRegularExpressions) { posInStr = regCol[0].Index; match.SetHitCount(regCol.Count); foreach (Match regExMatch in regCol) { matchLineFound.Matches.Add(new MatchResultLineMatch(regExMatch.Index, regExMatch.Length)); } } else { var lineMatches = libbSearch.Grep.RetrieveLineMatches(line, searchSpec); match.SetHitCount(lineMatches.Count); matchLineFound.Matches = lineMatches; } matchLineFound.ColumnNumber = 1; match.Matches.Add(matchLineFound); } } } } return(match); }
/// <summary> /// Searches the given file for the given search text. /// </summary> /// <param name="file">FileInfo object</param> /// <param name="searchSpec">ISearchSpec interface value</param> /// <param name="ex">Exception holder if error occurs</param> /// <returns>Hitobject containing grep results, null if on error</returns> /// <history> /// [Curtis_Beard] 07/28/2006 Created /// [Curtis_Beard] 05/25/2007 ADD: support for Exception object /// [Curtis_Beard] 03/31/2015 CHG: rework Grep/Matches /// </history> public MatchResult Grep(FileInfo file, ISearchSpec searchSpec, ref Exception ex) { // initialize Exception object to null ex = null; if (IsAvailable && IsUsable) { try { if (file.Exists) { //const int MARGINSIZE = 4; int count = 0; MatchResult match = null; int prevLine = 0; int prevPage = 0; //string _spacer = new string(' ', MARGINSIZE); //string _contextSpacer = string.Empty; //if (searchSpec.ContextLines > 0) //{ // _contextSpacer = new string(' ', MARGINSIZE); // _spacer = _contextSpacer.Substring(_contextSpacer.Length - MARGINSIZE - 2) + "> "; //} //else // _spacer = new string(' ', MARGINSIZE); // Open a given Word document as readonly // Note: Word 2003+ requires write mode since reading mode doesn't allow use of home/end keys to select text) object appversion = __WordApplication.GetType().InvokeMember("Version", BindingFlags.GetProperty, null, __WordApplication, null); double version = 0; double.TryParse(appversion.ToString(), out version); bool useReadOnly = version >= 12.00 ? false : true; object wordDocument = OpenDocument(file.FullName, useReadOnly); // Get Selection Property __WordSelection = __WordApplication.GetType().InvokeMember("Selection", BindingFlags.GetProperty, null, __WordApplication, null); // create range and find objects object range = GetProperty(wordDocument, "Content"); object find = GetProperty(range, "Find"); // setup find RunRoutine(find, "ClearFormatting", null); SetProperty(find, "Forward", true); SetProperty(find, "Text", searchSpec.SearchText); SetProperty(find, "MatchWholeWord", searchSpec.UseWholeWordMatching); SetProperty(find, "MatchCase", searchSpec.UseCaseSensitivity); // start find FindExecute(find); // keep finding text while ((bool)GetProperty(find, "Found") == true) { count += 1; if (count == 1) { // create hit object match = new MatchResult(file); } // since a hit was found and only displaying file names, quickly exit if (searchSpec.ReturnOnlyFileNames) break; // retrieve find information int start = (int)GetProperty(range, "Start"); int colNum = (int)Information(range, WdInformation.wdFirstCharacterColumnNumber); int lineNum = (int)Information(range, WdInformation.wdFirstCharacterLineNumber); int pageNum = (int)Information(range, WdInformation.wdActiveEndPageNumber); string line = GetFindTextLine(start); // don't add a hit if on same line if (!(prevLine == lineNum && prevPage == pageNum)) { // check for line numbers //if (searchSpec.IncludeLineNumbers) //{ // // setup line header // _spacer = "(" + string.Format("{0},{1}", lineNum, pageNum); // if (_spacer.Length <= 5) // { // _spacer = _spacer + new string(' ', 6 - _spacer.Length); // } // _spacer = _spacer + ") "; // //_contextSpacer = "(" + new string(' ', _spacer.Length - 3) + ") "; //} // remove any odd characters from the text line = RemoveSpecialCharacters(line); // add context lines before // if (__contextLines > 0){ // For i As int = __contextLines To 1 Step -1 // SetProperty(__WordSelection, "Start", start) // SelectionMoveUp(WdUnits.wdLine, i, WdMovementType.wdMove) // Dim cxt As string = GetFindTextLine() // cxt = RemoveSpecialCharacters(cxt) // if (Not HitExists(cxt, hit)){ // hit.Add(_contextSpacer & cxt & NEW_LINE, lineNum - i, 1) // End If // Next // End If // add line MatchResultLine matchLine = new MatchResultLine() { HasMatch = true, ColumnNumber = colNum, LineNumber = lineNum, Line = line }; var lineMatches = libAstroGrep.Grep.RetrieveLineMatches(line, searchSpec); match.SetHitCount(lineMatches.Count); matchLine.Matches = lineMatches; match.Matches.Add(matchLine); //match.Add(_spacer, line, lineNum, colNum); // add context lines after // if (__contextLines > 0){ // For i As int = 1 To __contextLines // SetProperty(__WordSelection, "Start", start) // SelectionMoveDown(WdUnits.wdLine, i, WdMovementType.wdMove) // Dim cxt As string = GetFindTextLine() // cxt = RemoveSpecialCharacters(cxt) // if (Not HitExists(cxt, hit)){ // hit.Add(_contextSpacer & cxt & NEW_LINE, lineNum + i, 1) // End If // Next // End If } //match.SetHitCount(); prevLine = lineNum; prevPage = pageNum; // find again FindExecute(find); } ReleaseSelection(); CloseDocument(wordDocument); return match; } else { string msg = string.Format("File does not exist: {0}", file.FullName); ex = new Exception(msg); Trace(msg); } } catch (Exception mainEx) { ex = mainEx; Trace(mainEx.ToString()); } } else { ex = new Exception("Plugin not available or usable."); Trace("Plugin not available or usable."); } return null; }
/// <summary> /// Retrieves the number of instances of searchText in the given line /// </summary> /// <param name="line">Line of text to search</param> /// <param name="searchSpec">Current ISearchSpec interface</param> /// <returns>Count of how many instances</returns> /// <history> /// [Curtis_Beard] 12/06/2005 Created /// [Curtis_Beard] 01/12/2007 FIX: check for correct position of IndexOf /// [Curtis_Beard] 03/05/2015 FIX: cleanup logic for whole word/case sensitive /// </history> public static List<MatchResultLineMatch> RetrieveLineMatches(string line, ISearchSpec searchSpec) { List<MatchResultLineMatch> lineMatches = new List<MatchResultLineMatch>(); int pos = line.IndexOf(searchSpec.SearchText, searchSpec.UseCaseSensitivity ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); while (pos > -1) { // retrieve parts of text string begin = line.Substring(0, pos); string end = line.Substring(pos + searchSpec.SearchText.Length); // do a check to see if begin and end are valid for wholeword searches bool _highlight = true; if (searchSpec.UseWholeWordMatching) { _highlight = WholeWordOnly(begin, end); } // found a hit if (_highlight) { MatchResultLineMatch lineMatch = new MatchResultLineMatch(pos, searchSpec.SearchText.Length); lineMatches.Add(lineMatch); } // Check remaining string for other hits in same line pos = line.IndexOf(searchSpec.SearchText, pos + 1, searchSpec.UseCaseSensitivity ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); } return lineMatches; }
/// <summary> /// Logs a start search message to log file. /// </summary> /// <param name="searchSpec">Current search specification</param> /// <param name="fileFilterSpec">Current file filter specification</param> /// <history> /// [Curtis_Beard] 05/15/2015 Initial /// [Curtis_Beard] 05/26/2015 FIX: 69, add performance setting, cache for file encoding detection /// </history> private void LogStartSearchMessage(ISearchSpec searchSpec, IFileFilterSpec fileFilterSpec) { StringBuilder searchTextOptions = new StringBuilder(); LogSearchOptionHelper(searchTextOptions, searchSpec.UseRegularExpressions, "regex"); LogSearchOptionHelper(searchTextOptions, searchSpec.UseCaseSensitivity, "case sensitive"); LogSearchOptionHelper(searchTextOptions, searchSpec.UseWholeWordMatching, "whole word"); LogSearchOptionHelper(searchTextOptions, searchSpec.UseNegation, "negation"); LogSearchOptionHelper(searchTextOptions, searchSpec.ReturnOnlyFileNames, "only file names"); LogSearchOptionHelper(searchTextOptions, searchSpec.ContextLines > 0, string.Format("{0} context lines", searchSpec.ContextLines)); if (searchTextOptions.Length > 0) { searchTextOptions.Insert(0, "["); searchTextOptions.Append("]"); } StringBuilder fileEncoding = new StringBuilder(); if (searchSpec.EncodingDetectionOptions.DetectFileEncoding) { fileEncoding.Append("["); fileEncoding.Append("detect encoding"); fileEncoding.AppendFormat(", performance set at {0}", Enum.GetName(typeof(EncodingOptions.Performance), GeneralSettings.EncodingPerformance).ToLower()); if (searchSpec.EncodingDetectionOptions.UseEncodingCache) { fileEncoding.Append(", cache enabled"); } fileEncoding.Append("]"); } LogClient.Instance.Logger.Info("Search started in '{0}'{1} against {2}{3} for {4}{5}", searchSpec.StartFilePaths != null && searchSpec.StartFilePaths.Length > 0 ? string.Join(", ", searchSpec.StartFilePaths) : string.Join(", ", searchSpec.StartDirectories), searchSpec.SearchInSubfolders ? "[include sub folders]" : "", fileFilterSpec.FileFilter, fileEncoding.ToString(), searchSpec.SearchText, searchTextOptions.ToString()); }
/// <summary> /// Searches the given file for the given search text. /// </summary> /// <param name="file">FileInfo object</param> /// <param name="searchSpec">ISearchSpec interface value</param> /// <param name="ex">Exception holder if error occurs</param> /// <returns>Hitobject containing grep results, null if on error</returns> /// <history> /// [Curtis_Beard] 07/28/2006 Created /// [Curtis_Beard] 05/25/2007 ADD: support for Exception object /// [Curtis_Beard] 03/31/2015 CHG: rework Grep/Matches /// </history> public MatchResult Grep(FileInfo file, ISearchSpec searchSpec, ref Exception ex) { // initialize Exception object to null ex = null; if (IsAvailable && IsUsable) { try { if (file.Exists) { //const int MARGINSIZE = 4; int count = 0; MatchResult match = null; int prevLine = 0; int prevPage = 0; //string _spacer = new string(' ', MARGINSIZE); //string _contextSpacer = string.Empty; //if (searchSpec.ContextLines > 0) //{ // _contextSpacer = new string(' ', MARGINSIZE); // _spacer = _contextSpacer.Substring(_contextSpacer.Length - MARGINSIZE - 2) + "> "; //} //else // _spacer = new string(' ', MARGINSIZE); // Open a given Word document as readonly // Note: Word 2003+ requires write mode since reading mode doesn't allow use of home/end keys to select text) object appversion = __WordApplication.GetType().InvokeMember("Version", BindingFlags.GetProperty, null, __WordApplication, null); double version = 0; double.TryParse(appversion.ToString(), out version); bool useReadOnly = version >= 12.00 ? false : true; object wordDocument = OpenDocument(file.FullName, useReadOnly); // Get Selection Property __WordSelection = __WordApplication.GetType().InvokeMember("Selection", BindingFlags.GetProperty, null, __WordApplication, null); // create range and find objects object range = GetProperty(wordDocument, "Content"); object find = GetProperty(range, "Find"); // setup find RunRoutine(find, "ClearFormatting", null); SetProperty(find, "Forward", true); SetProperty(find, "Text", searchSpec.SearchText); SetProperty(find, "MatchWholeWord", searchSpec.UseWholeWordMatching); SetProperty(find, "MatchCase", searchSpec.UseCaseSensitivity); // start find FindExecute(find); // keep finding text while ((bool)GetProperty(find, "Found") == true) { count += 1; if (count == 1) { // create hit object match = new MatchResult(file); } // since a hit was found and only displaying file names, quickly exit if (searchSpec.ReturnOnlyFileNames) { break; } // retrieve find information int start = (int)GetProperty(range, "Start"); int colNum = (int)Information(range, WdInformation.wdFirstCharacterColumnNumber); int lineNum = (int)Information(range, WdInformation.wdFirstCharacterLineNumber); int pageNum = (int)Information(range, WdInformation.wdActiveEndPageNumber); string line = GetFindTextLine(start); // don't add a hit if on same line if (!(prevLine == lineNum && prevPage == pageNum)) { // check for line numbers //if (searchSpec.IncludeLineNumbers) //{ // // setup line header // _spacer = "(" + string.Format("{0},{1}", lineNum, pageNum); // if (_spacer.Length <= 5) // { // _spacer = _spacer + new string(' ', 6 - _spacer.Length); // } // _spacer = _spacer + ") "; // //_contextSpacer = "(" + new string(' ', _spacer.Length - 3) + ") "; //} // remove any odd characters from the text line = RemoveSpecialCharacters(line); // add context lines before // if (__contextLines > 0){ // For i As int = __contextLines To 1 Step -1 // SetProperty(__WordSelection, "Start", start) // SelectionMoveUp(WdUnits.wdLine, i, WdMovementType.wdMove) // Dim cxt As string = GetFindTextLine() // cxt = RemoveSpecialCharacters(cxt) // if (Not HitExists(cxt, hit)){ // hit.Add(_contextSpacer & cxt & NEW_LINE, lineNum - i, 1) // End If // Next // End If // add line MatchResultLine matchLine = new MatchResultLine() { HasMatch = true, ColumnNumber = colNum, LineNumber = lineNum, Line = line }; var lineMatches = libAstroGrep.Grep.RetrieveLineMatches(line, searchSpec); match.SetHitCount(lineMatches.Count); matchLine.Matches = lineMatches; match.Matches.Add(matchLine); //match.Add(_spacer, line, lineNum, colNum); // add context lines after // if (__contextLines > 0){ // For i As int = 1 To __contextLines // SetProperty(__WordSelection, "Start", start) // SelectionMoveDown(WdUnits.wdLine, i, WdMovementType.wdMove) // Dim cxt As string = GetFindTextLine() // cxt = RemoveSpecialCharacters(cxt) // if (Not HitExists(cxt, hit)){ // hit.Add(_contextSpacer & cxt & NEW_LINE, lineNum + i, 1) // End If // Next // End If } //match.SetHitCount(); prevLine = lineNum; prevPage = pageNum; // find again FindExecute(find); } ReleaseSelection(); CloseDocument(wordDocument); return(match); } else { string msg = string.Format("File does not exist: {0}", file.FullName); ex = new Exception(msg); Trace(msg); } } catch (Exception mainEx) { ex = mainEx; Trace(mainEx.ToString()); } } else { ex = new Exception("Plugin not available or usable."); Trace("Plugin not available or usable."); } return(null); }
/// <summary> /// Searches the given file for the given search text. /// </summary> /// <param name="file">FileInfo object</param> /// <param name="searchSpec">ISearchSpec interface value</param> /// <param name="ex">Exception holder if error occurs</param> /// <returns>Hitobject containing grep results, null if on error</returns> /// <history> /// [Curtis_Beard] 10/17/2012 Created /// [Curtis_Beard] 03/31/2015 CHG: rework Grep/Matches /// </history> public MatchResult Grep(FileInfo file, ISearchSpec searchSpec, ref Exception ex) { // initialize Exception object to null ex = null; MatchResult match = null; if (Parser.IsParseable(file.FullName)) { string fileContent = Parser.Parse(file.FullName); if (!string.IsNullOrEmpty(fileContent)) { string[] lines = fileContent.Split(new char[] { '\n', '\r' }); for (int i = 0; i < lines.Length; i++) { string line = lines[i]; int posInStr = -1; Regex reg = null; MatchCollection regCol = null; if (searchSpec.UseRegularExpressions) { string pattern = string.Format("{0}{1}{0}", searchSpec.UseWholeWordMatching ? "\\b" : string.Empty, searchSpec.SearchText); RegexOptions options = searchSpec.UseCaseSensitivity ? RegexOptions.None : RegexOptions.IgnoreCase; reg = new Regex(pattern, options); regCol = reg.Matches(line); if (regCol.Count > 0) { posInStr = 1; } } else { // If we are looking for whole worlds only, perform the check. if (searchSpec.UseWholeWordMatching) { reg = new Regex("\\b" + Regex.Escape(searchSpec.SearchText) + "\\b", searchSpec.UseCaseSensitivity ? RegexOptions.None : RegexOptions.IgnoreCase); // if match is found, also check against our internal line hit count method to be sure they are in sync Match mtc = reg.Match(line); if (mtc != null && mtc.Success && libAstroGrep.Grep.RetrieveLineMatches(line, searchSpec).Count > 0) { posInStr = mtc.Index; } } else { posInStr = line.IndexOf(searchSpec.SearchText, searchSpec.UseCaseSensitivity ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); } } if (posInStr > -1) { if (match == null) { match = new MatchResult(file); // found hit in file so just return if (searchSpec.ReturnOnlyFileNames) { break; } } var matchLineFound = new MatchResultLine() { Line = line, LineNumber = -1, HasMatch = true }; if (searchSpec.UseRegularExpressions) { posInStr = regCol[0].Index; match.SetHitCount(regCol.Count); foreach (Match regExMatch in regCol) { matchLineFound.Matches.Add(new MatchResultLineMatch(regExMatch.Index, regExMatch.Length)); } } else { var lineMatches = libAstroGrep.Grep.RetrieveLineMatches(line, searchSpec); match.SetHitCount(lineMatches.Count); matchLineFound.Matches = lineMatches; } matchLineFound.ColumnNumber = 1; match.Matches.Add(matchLineFound); } } } } return match; }
public Grep(ISearchSpec searchSpec) { SearchSpec = searchSpec; MatchResults = new List <MatchResult>(); }