/// <summary> /// Preprocesses the search options and returns an opaque object /// that holds the state needed to efficiently search many times using the search options. /// Different threads can not share the returned state object. Each thread has to call this method. /// </summary> public static SearchState BeginSearch(this Options options, IRegexFactory regexFactory, bool timeboxedMatching = false) { SearchState ret = new SearchState() { options = options, contentTypeMask = MessageFlag.ContentTypeMask & options.ContentTypes, }; if (!string.IsNullOrEmpty(options.Template)) { if (options.Regexp || useRegexsForSimpleTemplates) { ReOptions reOpts = ReOptions.AllowPatternWhitespaces; if (!options.MatchCase) { reOpts |= ReOptions.IgnoreCase; } if (options.ReverseSearch) { reOpts |= ReOptions.RightToLeft; } if (timeboxedMatching) { reOpts |= ReOptions.Timeboxed; } try { ret.re = regexFactory.Create( options.Regexp ? options.Template : System.Text.RegularExpressions.Regex.Escape(options.Template), reOpts); } catch (Exception) { throw new TemplateException(); } } else { if (!options.MatchCase) { ret.options.Template = ret.options.Template.ToLower(); } } } return(ret); }
public static MatchedTextRange?SearchInMessageText( this SearchState state, IMessage msg, int?startTextPosition = null) { MessageFlag msgFlags = msg.Flags; if ((msgFlags & state.contentTypeMask) == 0) { return(null); } if (!state.options.Scope.ContainsMessage(msg)) { return(null); } StringSlice sourceText = state.options.MessageTextGetter(msg).Text; return(SearchInText(state, sourceText, startTextPosition)); }
public static MatchedTextRange?SearchInText( this SearchState state, StringSlice text, int?startTextPosition) { IRegex re = state.re; // matched string position int matchBegin = 0; // index of the first matched char int matchEnd = 0; // index of following after the last matched one bool wholeTextMatched = false; if (!string.IsNullOrEmpty(state.options.Template)) // empty/null template means that text matching isn't required, i.e. match any input { int textPos; if (startTextPosition.HasValue) { textPos = startTextPosition.Value; } else if (state.options.ReverseSearch) { textPos = text.Length; } else { textPos = 0; } for (; ;) { if (re != null) { if (!re.Match(text, textPos, ref state.searchMatch)) { return(null); } matchBegin = state.searchMatch.Index; matchEnd = matchBegin + state.searchMatch.Length; } else { StringComparison cmp = state.options.MatchCase ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase; int i; // todo: use running hash if (state.options.ReverseSearch) { i = text.LastIndexOf(state.options.Template, textPos, cmp); } else { i = text.IndexOf(state.options.Template, textPos, cmp); } if (i < 0) { return(null); } matchBegin = i; matchEnd = matchBegin + state.options.Template.Length; } if (state.options.WholeWord && !IsWordBoundary(text, matchBegin, matchEnd)) { textPos = state.options.ReverseSearch ? matchBegin : matchEnd; continue; } break; } } else { matchBegin = 0; matchEnd = text.Length; wholeTextMatched = true; } return(new MatchedTextRange(text, matchBegin, matchEnd, wholeTextMatched)); }