/// <summary> /// Returns a regular expression that matches this regular expression zero or more times.</summary> /// <param name="greedy"> /// <c>true</c> to prioritise longer matches (“greedy” matching); <c>false</c> to prioritise shorter matches /// (“non-greedy” matching).</param> protected TManyGenerex repeatInfinite <TManyGenerex, TManyGenerexMatch>(bool greedy) where TManyGenerex : GenerexWithResultBase <T, IEnumerable <TResult>, TManyGenerex, TManyGenerexMatch> where TManyGenerexMatch : GenerexMatch <T, IEnumerable <TResult> > { Func <matcher, GenerexWithResultBase <T, IEnumerable <TResult>, TManyGenerex, TManyGenerexMatch> .matcher> createRepeatInfiniteMatcher = (matcher inner) => { GenerexWithResultBase <T, IEnumerable <TResult>, TManyGenerex, TManyGenerexMatch> .matcher newMatcher = null; if (greedy) { newMatcher = (input, startIndex) => inner(input, startIndex).SelectMany(m => newMatcher(input, startIndex + m.Length) .Select(m2 => new LengthAndResult <IEnumerable <TResult> >(m.Result.Concat(m2.Result), m.Length + m2.Length))) .Concat(new LengthAndResult <IEnumerable <TResult> >(Enumerable.Empty <TResult>(), 0)); } else { newMatcher = (input, startIndex) => new LengthAndResult <IEnumerable <TResult> >(Enumerable.Empty <TResult>(), 0) .Concat(inner(input, startIndex).SelectMany(m => newMatcher(input, startIndex + m.Length) .Select(m2 => new LengthAndResult <IEnumerable <TResult> >(m.Result.Concat(m2.Result), m.Length + m2.Length)))); } return(newMatcher); }; return(GenerexWithResultBase <T, IEnumerable <TResult>, TManyGenerex, TManyGenerexMatch> .Constructor( createRepeatInfiniteMatcher(_forwardMatcher), createRepeatInfiniteMatcher(_backwardMatcher))); }
/// <summary> /// Processes each match of this regular expression by running each result object through a provided selector.</summary> /// <typeparam name="TOtherGenerex"> /// Generex type to return.</typeparam> /// <typeparam name="TOtherGenerexMatch"> /// Generex match type that corresponds to <typeparamref name="TOtherGenerex"/></typeparam> /// <typeparam name="TOtherResult"> /// Type of the object returned by <paramref name="selector"/>.</typeparam> /// <param name="selector"> /// Function to process a regular expression match.</param> protected TOtherGenerex processRaw <TOtherGenerex, TOtherGenerexMatch, TOtherResult>(Func <TResult, TOtherResult> selector) where TOtherGenerex : GenerexWithResultBase <T, TOtherResult, TOtherGenerex, TOtherGenerexMatch> where TOtherGenerexMatch : GenerexMatch <T, TOtherResult> { return(GenerexWithResultBase <T, TOtherResult, TOtherGenerex, TOtherGenerexMatch> .Constructor( (input, startIndex) => _forwardMatcher(input, startIndex).Select(m => new LengthAndResult <TOtherResult>(selector(m.Result), m.Length)), (input, startIndex) => _backwardMatcher(input, startIndex).Select(m => new LengthAndResult <TOtherResult>(selector(m.Result), m.Length)) )); }
/// <summary> /// Returns a regular expression that only matches if the subarray matched by this regular expression also matches /// the specified matching function, and if so, combines the first match’s result object with the second match /// using a specified selector.</summary> /// <typeparam name="TOtherResult"> /// The type of the result object associated with each match returned by <paramref name="innerMatch"/>.</typeparam> /// <typeparam name="TOtherGenerex"> /// The type of the other regular expression. (This is either <see cref="Generex{T,TResult}"/> or <see /// cref="Stringerex{TResult}"/>, but with <typeparamref name="TOtherResult"/> in place of <c>TResult</c>.)</typeparam> /// <typeparam name="TOtherGenerexMatch"> /// The type of the match object for the other regular expression. (This is either <see /// cref="GenerexMatch{T,TResult}"/> or <see cref="StringerexMatch{TResult}"/>, but with <typeparamref /// name="TOtherResult"/> in place of <c>TResult</c>.)</typeparam> /// <typeparam name="TCombinedResult"> /// The type of the combined result object returned by <paramref name="selector"/>.</typeparam> /// <typeparam name="TCombinedGenerex"> /// The type of the new regular expression to be returned. (This is either <see cref="Generex{T,TResult}"/> or /// <see cref="Stringerex{TResult}"/>, but with <typeparamref name="TCombinedResult"/> in place of /// <c>TResult</c>.)</typeparam> /// <typeparam name="TCombinedGenerexMatch"> /// The type of the match object for the regular expression to be returned. (This is either <see /// cref="GenerexMatch{T,TResult}"/> or <see cref="StringerexMatch{TResult}"/>, but with <typeparamref /// name="TCombinedResult"/> in place of <c>TResult</c>.)</typeparam> /// <param name="innerMatch"> /// A function that runs on the subarray matched by this regular expression and returns either a match or /// <c>null</c>.</param> /// <param name="selector"> /// A selector function that combines the result object associated with the match of this regular expression, and /// the match returned by <paramref name="innerMatch"/>, into a new result object.</param> /// <remarks> /// The match object passed into <paramref name="selector"/> is the same that <paramref name="innerMatch"/> /// returned. Therefore, its <see cref="GenerexMatch{T}.Index"/> property refers to the index within the subarray, /// not the original input sequence.</remarks> protected TCombinedGenerex and <TOtherResult, TOtherGenerex, TOtherGenerexMatch, TCombinedResult, TCombinedGenerex, TCombinedGenerexMatch>(Func <T[], TOtherGenerexMatch> innerMatch, Func <TResult, TOtherGenerexMatch, TCombinedResult> selector) where TOtherGenerex : GenerexWithResultBase <T, TOtherResult, TOtherGenerex, TOtherGenerexMatch> where TOtherGenerexMatch : GenerexMatch <T, TOtherResult> where TCombinedGenerex : GenerexWithResultBase <T, TCombinedResult, TCombinedGenerex, TCombinedGenerexMatch> where TCombinedGenerexMatch : GenerexMatch <T, TCombinedResult> { return(GenerexWithResultBase <T, TCombinedResult, TCombinedGenerex, TCombinedGenerexMatch> .Constructor( (input, startIndex) => _forwardMatcher(input, startIndex).SelectMany(m => { var subarray = input.Subarray(startIndex, getLength(m)); var submatch = innerMatch(subarray); return submatch == null ? Enumerable.Empty <LengthAndResult <TCombinedResult> >() : new[] { new LengthAndResult <TCombinedResult>(selector(m.Result, submatch), m.Length) }; }), (input, startIndex) => _backwardMatcher(input, startIndex).SelectMany(m => { var length = getLength(m); var subarray = input.Subarray(startIndex + length, -length); var submatch = innerMatch(subarray); return submatch == null ? Enumerable.Empty <LengthAndResult <TCombinedResult> >() : new[] { new LengthAndResult <TCombinedResult>(selector(m.Result, submatch), m.Length) }; }) )); }
/// <summary> /// Returns a regular expression that matches this regular expression any number of times within specified /// boundaries.</summary> /// <param name="min"> /// Minimum number of times to match.</param> /// <param name="max"> /// Maximum number of times to match.</param> /// <param name="greedy"> /// <c>true</c> to prioritise longer matches (“greedy” matching); <c>false</c> to prioritise shorter matches /// (“non-greedy” matching).</param> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="min"/> is negative.</exception> /// <exception cref="ArgumentException"> /// <paramref name="max"/> is smaller than <paramref name="min"/>.</exception> protected TManyGenerex repeatBetween <TManyGenerex, TManyGenerexMatch>(int min, int max, bool greedy) where TManyGenerex : GenerexWithResultBase <T, IEnumerable <TResult>, TManyGenerex, TManyGenerexMatch> where TManyGenerexMatch : GenerexMatch <T, IEnumerable <TResult> > { if (min < 0) { throw new ArgumentOutOfRangeException("'min' cannot be negative.", "min"); } if (max < min) { throw new ArgumentException("'max' cannot be smaller than 'min'.", "max"); } var rm = new repeatMatcher { Greedy = greedy, MinTimes = min, MaxTimes = max, InnerForwardMatcher = _forwardMatcher, InnerBackwardMatcher = _backwardMatcher }; return(GenerexWithResultBase <T, IEnumerable <TResult>, TManyGenerex, TManyGenerexMatch> .Constructor(rm.ForwardMatcher, rm.BackwardMatcher)); }
/// <summary> /// Returns a regular expression that matches this regular expression, followed by the specified one, and /// generates a result object that combines the original two matches.</summary> protected TCombinedGenerex thenRaw <TOtherGenerex, TOtherGenerexMatch, TOtherResult, TCombinedGenerex, TCombinedGenerexMatch, TCombinedResult>( GenerexWithResultBase <T, TOtherResult, TOtherGenerex, TOtherGenerexMatch> other, Func <TResult, TOtherResult, TCombinedResult> selector) where TOtherGenerex : GenerexWithResultBase <T, TOtherResult, TOtherGenerex, TOtherGenerexMatch> where TOtherGenerexMatch : GenerexMatch <T, TOtherResult> where TCombinedGenerex : GenerexWithResultBase <T, TCombinedResult, TCombinedGenerex, TCombinedGenerexMatch> where TCombinedGenerexMatch : GenerexMatch <T, TCombinedResult> { if (other == null) { throw new ArgumentNullException("other"); } if (selector == null) { throw new ArgumentNullException("selector"); } return(GenerexWithResultBase <T, TCombinedResult, TCombinedGenerex, TCombinedGenerexMatch> .Constructor( (input, startIndex) => _forwardMatcher(input, startIndex).SelectMany(m => other._forwardMatcher(input, startIndex + m.Length) .Select(m2 => new LengthAndResult <TCombinedResult>(selector(m.Result, m2.Result), m.Length + m2.Length))), (input, startIndex) => other._backwardMatcher(input, startIndex).SelectMany(m2 => _backwardMatcher(input, startIndex + m2.Length) .Select(m => new LengthAndResult <TCombinedResult>(selector(m.Result, m2.Result), m.Length + m2.Length))) )); }