public ParsedMatch <T>?TryMatch(StringPart stringPart) { var index = stringPart.Target.IndexOf(_needle, stringPart.StartIndex, stringPart.Length, _comparison); if (index >= 0) { var stringPartMatch = stringPart.Slice(index, _needle.Length); return(new ParsedMatch <T>(stringPartMatch, _transform(stringPartMatch))); } return(null); }
public static IEnumerable <ParsedMatch <T> > MatchAll <T>(this IMatcher <T> matcher, StringPart stringPart, Func <StringPart, T> transformFallback) { // Loop through segments divided by individual matches var currentIndex = stringPart.StartIndex; while (currentIndex < stringPart.EndIndex) { // Find a match within this segment var match = matcher.TryMatch(stringPart.Slice(currentIndex, stringPart.EndIndex - currentIndex)); // If there's no match - break if (match == null) { break; } // If this match doesn't start immediately at current index - transform and yield fallback first if (match.StringPart.StartIndex > currentIndex) { var fallbackPart = stringPart.Slice(currentIndex, match.StringPart.StartIndex - currentIndex); yield return(new ParsedMatch <T>(fallbackPart, transformFallback(fallbackPart))); } // Yield match yield return(match); // Shift current index to the end of the match currentIndex = match.StringPart.StartIndex + match.StringPart.Length; } // If EOL wasn't reached - transform and yield remaining part as fallback if (currentIndex < stringPart.EndIndex) { var fallbackPart = stringPart.Slice(currentIndex); yield return(new ParsedMatch <T>(fallbackPart, transformFallback(fallbackPart))); } }
public ParsedMatch <T>?TryMatch(StringPart stringPart) { var match = _regex.Match(stringPart.Target, stringPart.StartIndex, stringPart.Length); if (!match.Success) { return(null); } // Overload regex.Match(string, int, int) doesn't take the whole string into account, // it effectively functions as a match check on a substring. // Which is super weird because regex.Match(string, int) takes the whole input in context. // So in order to properly account for ^/$ regex tokens, we need to make sure that // the expression also matches on the bigger part of the input. if (!_regex.IsMatch(stringPart.Target.Substring(0, stringPart.EndIndex), stringPart.StartIndex)) { return(null); } var stringPartMatch = stringPart.Slice(match.Index, match.Length); return(new ParsedMatch <T>(stringPartMatch, _transform(stringPartMatch, match))); }