//this is wicked fast
//do not refactor extract methods from this if you want to keep the speed
public MatchResult Match(string text, int startIndex)
{
if (string.IsNullOrEmpty(text))
{
throw new ArgumentNullException(text);
}
var lastMatch = new MatchResult {
Text = text
};
int textLength = text.Length;
for (int currentIndex = startIndex; currentIndex < textLength; currentIndex++)
{
//call any prefixless patternmatchers
#region HasExpressions
if (root.FirstExpression != null)
{
//begin with the first expression of the _root node_
PatternMatchReference patternMatcherReference = root.FirstExpression;
while (patternMatcherReference != null)
{
int patternMatchIndex = patternMatcherReference.Matcher.Match(text, currentIndex);
if (patternMatchIndex > 0 && patternMatchIndex > lastMatch.Length)
{
bool leftIsSeparator = currentIndex == 0 ? true : separatorCharLookup[text[currentIndex - 1]];
bool rightIsSeparator = (currentIndex + patternMatchIndex) == textLength ? true : separatorCharLookup[text[currentIndex + patternMatchIndex]];
if (!patternMatcherReference.NeedSeparators || (leftIsSeparator && rightIsSeparator))
{
lastMatch.Index = currentIndex;
lastMatch.Length = patternMatchIndex;
lastMatch.Found = true;
lastMatch.Tags = patternMatcherReference.Tags;
}
}
patternMatcherReference = patternMatcherReference.NextSibling;
}
}
#endregion
//lookup the first token tree node
TokenTreeNode node = nodes[text[currentIndex]];
if (node == null)
{
if (lastMatch.Found)
{
break;
}
continue;
}
for (int matchIndex = currentIndex + 1; matchIndex <= textLength; matchIndex++)
{
//call patternmatchers for the current prefix
#region HasExpressions
if (node.FirstExpression != null)
{
//begin with the first expression of the _current node_
PatternMatchReference patternMatcherReference = node.FirstExpression;
while (patternMatcherReference != null)
{
int patternMatchIndex = patternMatcherReference.Matcher.Match(text, matchIndex);
if (patternMatchIndex > 0 && patternMatchIndex > lastMatch.Length)
{
bool leftIsSeparator = currentIndex == 0 ? true : separatorCharLookup[text[currentIndex - 1]];
bool rightIsSeparator = (currentIndex + patternMatchIndex + matchIndex) == textLength ? true : separatorCharLookup[text[currentIndex + patternMatchIndex + matchIndex]];
if (!patternMatcherReference.NeedSeparators || (leftIsSeparator && rightIsSeparator))
{
lastMatch.Index = currentIndex;
lastMatch.Length = patternMatchIndex + matchIndex - currentIndex;
lastMatch.Found = true;
lastMatch.Tags = patternMatcherReference.Tags;
}
}
patternMatcherReference = patternMatcherReference.NextSibling;
}
}
#endregion
#region IsEndNode
if (node.IsEnd && matchIndex - currentIndex >= lastMatch.Length)
{
bool leftIsSeparator = currentIndex == 0 ? true : separatorCharLookup[text[currentIndex - 1]];
bool rightIsSeparator = matchIndex == textLength ? true : separatorCharLookup[text[matchIndex]];
if (!node.NeedSeparators || (leftIsSeparator && rightIsSeparator))
{
lastMatch.Index = currentIndex;
lastMatch.Tags = node.Tags;
lastMatch.Found = true;
lastMatch.Length = matchIndex - currentIndex;
//TODO:perform case test here , case sensitive words might be matched even if they have incorrect case
if (currentIndex + lastMatch.Length == textLength)
{
break;
}
}
}
#endregion
//try fetch a node at this index
node = node.GetNextNode(textLookup[text[matchIndex]]);
//we found no node on the lookupindex or none of the siblingnodes at that index matched the current char
if (node == null)
{
break; // continue with the next character
}
}
//return last match
if (lastMatch.Found)
{
return(lastMatch);
}
}
if (lastMatch.Found)
{
return(lastMatch);
}
//no match was found
return(MatchResult.NoMatch);
}