public bool IsMatch(string allChars, int currentPosition, out int newPosition) { var currentChar = allChars[currentPosition]; newPosition = currentPosition + 1; return(GlobStringReader.IsPathSeperator(currentChar)); }
public MatchInfo Evaluate(string text) { EnqueueTokens(_Tokens); _text = text; IGlobToken token = null; using (_Reader = new GlobStringReader(text)) { while (_TokenQueue.Any()) { token = _TokenQueue.Dequeue(); token.Accept(this); if (!Success) { return(FailedResult(token)); } } // if all tokens matched but still more text then fail! if (_Reader.Peek() != -1) { return(FailedResult(null)); } // Success. return(SuccessfulResult()); } }
public bool IsMatch(string allChars, int currentPosition, out int newPosition) { newPosition = currentPosition + 1; var currentChar = allChars[currentPosition]; if (GlobStringReader.IsPathSeperator(currentChar)) { return(false); } return(true); }
public void Visit(AnyCharacterToken token) { Success = false; var read = _Reader.Read(); if (read == -1) { return; } var currentChar = (char)read; if (GlobStringReader.IsPathSeparator(currentChar)) { return; } AddMatch(new GlobTokenMatch() { Token = token, Value = currentChar.ToString() }); }
public void Visit(WildcardToken token) { // When * encountered, // Dequees all remaining tokens and passes them to a nested Evaluator. // Keeps seing if the nested evaluator will match, and if it doesn't then // will consume / match against one character, and retry. // Exits when match successful, or when the end of the current path segment is reached. GlobTokenMatch match = null; match = new GlobTokenMatch() { Token = token }; AddMatch(match); var remainingText = _Reader.ReadToEnd(); int endOfSegmentPos; using (var pathReader = new GlobStringReader(remainingText)) { var thisPath = pathReader.ReadPathSegment(); endOfSegmentPos = pathReader.CurrentIndex; } var remaining = _TokenQueue.ToArray(); // if no more tokens remaining then just return as * matches the rest of the segment. if (remaining.Length == 0) { this.Success = true; match.Value = remainingText; return; } // we have to attempt to match the remaining tokens, and if they dont all match, // then consume a character, until we have matched the entirity of this segment. var matchedText = new StringBuilder(endOfSegmentPos); var nestedEval = new GlobTokenMatchAnalysisEvaluator(remaining); var pathSegments = new List <string>(); // we keep a record of text that this wildcard matched in order to satisfy the // greatest number of child token matches. var bestMatchText = new StringBuilder(endOfSegmentPos); IList <GlobTokenMatch> bestMatches = null; // the most tokens that were matched. for (int i = 0; i <= endOfSegmentPos; i++) { var matchInfo = nestedEval.Evaluate(remainingText); if (matchInfo.Success) { break; } // match a single character matchedText.Append(remainingText[0]); // re-attempt matching of child tokens against this remaining string. remainingText = remainingText.Substring(1); // If we have come closer to matching, record our best results. if ((bestMatches == null && matchInfo.Matches.Any()) || (bestMatches != null && bestMatches.Count < matchInfo.Matches.Length)) { bestMatches = matchInfo.Matches.ToArray(); bestMatchText.Clear(); bestMatchText.Append(matchedText.ToString()); } } this.Success = nestedEval.Success; if (nestedEval.Success) { // add all child matches. this.MatchedTokens.AddRange(nestedEval.MatchedTokens); } else { // add the most tokens we managed to match. if (bestMatches != null && bestMatches.Any()) { this.MatchedTokens.AddRange(bestMatches); } } match.Value = matchedText.ToString(); _TokenQueue.Clear(); }
public bool IsMatch(string allChars, int currentPosition, out int newPosition) #endif { // We shortcut to success for a ** in some special cases:- // 1. The remaining tokens don't need to consume a minimum number of chracters in order to match. // We shortcut to failure for a ** in some special cases:- // A) The token was parsed with a leading path separator (i.e '/**' and the current charater we are matching from isn't a path separator. newPosition = currentPosition; // A) If leading seperator then current character needs to be that seperator. char currentChar = allChars[currentPosition]; if (_token.LeadingPathSeparator != null) { if (!GlobStringReader.IsPathSeparator(currentChar)) { // expected separator. return(false); } //else //{ // advance current position to match the leading separator. currentPosition = currentPosition + 1; //} } else { // no leading seperator, means ** used at start of pattern not /** used within pattern. // If **/ is used for start of pattern then input string doesn't need to start with a / or \ and it will be matched. // i.e **/foo/bar will match foo/bar or /foo/bar. // where as /**/foo/bar will not match foo/bar it will only match /foo/bar. currentChar = allChars[currentPosition]; if (GlobStringReader.IsPathSeparator(currentChar)) { // advance current position to match the leading separator. currentPosition = currentPosition + 1; } } // 1. if no more tokens require matching we match. if (_subEvaluator.ConsumesMinLength == 0) { newPosition = allChars.Length; return(true); } // Because we know we have more tokens in the pattern (subevaluators) - those will require a minimum amount of characters to match (could be 0 too). // We can therefore calculate a "max" character position that we can match to, as if we exceed that position the remaining tokens cant possibly match. int maxPos = (allChars.Length - _subEvaluator.ConsumesMinLength); // If all of the remaining tokens have a precise length, we can calculate the exact character that we need to macth to in the string. // Otherwise we have to test at multiple character positions until we find a match (less efficient) if (!_subEvaluator.ConsumesVariableLength) { // Fixed length. // As we can only match full segments, make sure character before chacracter at max pos is a separator, if (maxPos > 0) { char mustMatchUntilChar = allChars[maxPos - 1]; if (!GlobStringReader.IsPathSeparator(mustMatchUntilChar)) { // can only match full segments. return(false); } } // Advance position to max pos. currentPosition = maxPos; return(_subEvaluator.IsMatch(allChars, currentPosition, out newPosition)); } else { // Remaining tokens match a variable length of the test string. // We iterate each position (within acceptable range) and test at each position. bool isMatch; currentChar = allChars[currentPosition]; // If the ** token was parsed with a trailing slash - i.e "**/" then we need to match past it before we test remainijng tokens. // special exception if **/ is at start of pattern, as then the input string need not have any path separators. if (_token.TrailingPathSeparator != null) { if (GlobStringReader.IsPathSeparator(currentChar)) { // match the separator. currentPosition = currentPosition + 1; } } // Match until maxpos, is reached. while (currentPosition <= maxPos) { // Test at current position. isMatch = _subEvaluator.IsMatch(allChars, currentPosition, out newPosition); if (isMatch) { return(isMatch); } if (currentPosition == maxPos) { return(false); } // Iterate until we hit a separator or maxPos. while (currentPosition < maxPos) { currentPosition = currentPosition + 1; currentChar = allChars[currentPosition]; if (GlobStringReader.IsPathSeparator(currentChar)) { // match the separator. currentPosition = currentPosition + 1; break; } } } } return(false); }