internal TagQuery(string[] tags, TagMatchMode mode) { this.TagMatchMode = mode; tags = tags ?? Empty; this.Tags = tags; }
private static TagMatch GetTagMatchRight(IList<string> tagList, IList<IList<string>> matchingTagList, TagMatchMode mode) { int loopCount = 1; // default to one - gets overridden if continueOnMiss == true TagMatch match = new TagMatch(); match.Tag = null; match.Length = 0; match.Index = -1; bool requireFirstTagMatch = (TagMatchMode.REQUIRE_FIRST_MATCH & mode) == TagMatchMode.REQUIRE_FIRST_MATCH; // first only is the default. Override it to make sure we check all input strings until we get a match or checked them all. if (!requireFirstTagMatch) { loopCount = tagList.Count; } // loop through input tags - <i> will be current tag String (or current partial tag string) for (int i = 0; i < loopCount; i++) { int iInverse = tagList.Count - 1 - i; // loop through all the matching tags for (int j = 0; j < matchingTagList.Count; j++) { // check if tags can "fit" current matchingTag (if the current matchingTag is bigger than input tagList, then obviously it cannot match) if ((tagList.Count - i) >= matchingTagList[j].Count) { // remove the <i>th last elements in tagList (they've already been dismissed) List<string> uncheckedTagsList = ((List<string>)tagList).GetRange(0, iInverse + 1); bool tagMatch = isTagMatch(uncheckedTagsList, matchingTagList[j], mode | TagMatchMode.RIGHT_TO_LEFT); if (tagMatch == true) { match.Index = iInverse; match.Length = matchingTagList[j].Count; match.MatchIndex = j; match.Tag = new Tag(uncheckedTagsList.GetRange(match.Index, match.Length)); return match; } } } } return match; }
private static bool isTagMatch(IList<string> tagList, IList<string> referenceTag, TagMatchMode mode) { bool matchCase = (TagMatchMode.CASE_SENSITIVE & mode) == TagMatchMode.CASE_SENSITIVE; bool matchFromRight = (TagMatchMode.RIGHT_TO_LEFT & mode) == TagMatchMode.RIGHT_TO_LEFT; // offset is used to make sure we check the right-most/upperbound of the tagList. int offsetTagList = 0; if (matchFromRight && (tagList.Count > referenceTag.Count)) { offsetTagList = tagList.Count - referenceTag.Count; } // loop through all strings in the reference matching tag for (int i = 0; i < referenceTag.Count; i++) { // compare strings - added complexity due to case sensitivity check. if ((matchCase && (tagList[offsetTagList + i] != referenceTag[i])) || (!matchCase && (tagList[offsetTagList + i].ToUpper() != referenceTag[i].ToUpper()))) { // didnt match return false; } else if (i == referenceTag.Count - 1) { // matchTag.Count - 1 == upperbound of matchTag list. // match - we've looped from upperbound to 0 without a single mismatch (because that would've returned false above) return true; } } return false; }
public static TagMatches GetTagMatchesRight(IList<string> inputTagStringList, IList<string> acceptedTagList, TagMatchMode mode) { IList<IList<string>> haystackTagList = GetSortedTagList(acceptedTagList); List<string> needleTagList = inputTagStringList.ToList(); bool noSkipping = (TagMatchMode.REQUIRE_FIRST_MATCH & mode) == TagMatchMode.REQUIRE_FIRST_MATCH; bool sequentialOnly = (TagMatchMode.SUCCESSIVE & mode) == TagMatchMode.SUCCESSIVE; TagMatch match; TagMatches matches = new TagMatches(); // TODO: This function (and original) seriously needs some sanity checks. // Actually maybe not... i was thinking about noSkipping and match.length == 0 below - but gettagmatch with !noSkipping would search the entire input list - IT handles the skipping while (needleTagList.Count > 0) { match = GetTagMatchRight(needleTagList, haystackTagList, mode); if (match.Length <= 0) { // We didn't get a match. // if noSkipping : Terminate! We require all tags to match! // if !noSkipping : Terminate! We're allowed to skip tags, and yet we didn't get a match - that means we must've gone through to the end. // All that's left to do is add tag string list to unmatched tags and return matches. break; } else if (match.Length > 0) { // got match // We got a match, but it wasnt the first tag (this MUST mean noSkipping is False) if (match.Index + match.Length < needleTagList.Count - 1 && sequentialOnly && matches.Count > 0) { // match was not first tag. This is a problem if sequentialOnly == true, UNLESS this is the first match! // Lets take sequential matches we got and go home merrily. break; } needleTagList.RemoveRange(match.Index + match.Length, needleTagList.Count - (match.Index + match.Length)); // We got a match. It's Index may be greater than 0, however in the block above ALL unmatched tags BEFORE the match were removed. // So effectively, the matched tag is at Index == 0. // add the matched tag to Matches. matches.Matches.Add(match); // remove the tags we just matched from the tag list // again: index is 0 because all preceeding unmatched tags were removed needleTagList.RemoveRange(match.Index, match.Length); // remove the matched tag too! This way it will never be matched again! haystackTagList.RemoveAt(match.MatchIndex); } } // add a string for the remaining tags we havent matched. //if (needleTagList.Count > 0) // matches.UnmatchedTagSequences.Add(TagListToString(needleTagList)); matches.Matches = matches.Matches.Reverse().ToList(); return matches; }