/// <summary> /// If a matcher in the sequence doesn't match, then it doesn't match /// </summary> /// <param name="context"></param> /// <param name="start"></param> /// <returns></returns> public override MatchResult Matches(MatchContext context, TokenEntity startToken, PatternMatcher nextPatternMatcher) { var tokenEntity = startToken; // try to match each element in the sequence. int start = startToken?.Start ?? 0; int end = 0; for (int iPattern = 0; iPattern < PatternMatchers.Count; iPattern++) { var matchResult = new MatchResult(false, this, tokenEntity); var patternMatcher = PatternMatchers[iPattern]; if (patternMatcher.ContainsWildcard()) { // look ahead to non wild card nextPatternMatcher = PatternMatchers.Skip(iPattern).Where(pm => !pm.ContainsWildcard()).FirstOrDefault(); // run wildcard pattern matcher matchResult = patternMatcher.Matches(context, tokenEntity, nextPatternMatcher); // if the match was not the wildcard pattern, then advance to that. if (matchResult.NextPatternMatch != null) { Debug.Assert(matchResult.NextPatternMatch.PatternMatcher == nextPatternMatcher); matchResult = matchResult.NextPatternMatch; iPattern = PatternMatchers.IndexOf(matchResult.PatternMatcher); Debug.Assert(iPattern >= 0); } } else { matchResult = patternMatcher.Matches(context, tokenEntity, nextPatternMatcher); } // if the element did not match, then sequence is bad, return failure if (matchResult.Matched == false) { return(new MatchResult(false, this, tokenEntity)); } tokenEntity = matchResult.NextToken; end = Math.Max(matchResult.End, end); } return(new MatchResult(true, this, tokenEntity, start, end)); }
/// <summary> /// Match and add entity as appropriate. /// </summary> /// <param name="matchContext">match context.</param> /// <param name="tokenEntity">token entity</param> /// <returns>matchresult</returns> public abstract MatchResult Matches(MatchContext matchContext, TokenEntity tokenEntity, PatternMatcher nextPatternMatcher);
/// <summary> /// /// </summary> /// <param name="pattern">pattern to parse</param> /// <returns></returns> public PatternMatcher Parse(string pattern, bool defaultFuzzyMatch = false, Ordinality ordinality = Ordinality.One, int maxMatches = 16) { OrdinalityPatternMatcher ordinalityPatternMatcher = new OrdinalityPatternMatcher(ordinality, maxMatches); SequencePatternMatcher sequence = new SequencePatternMatcher(); StringBuilder sb = new StringBuilder(); var fuzzyMatch = defaultFuzzyMatch; var chars = pattern.GetEnumerator(); while (chars.MoveNext()) { char ch = chars.Current; bool repeatChar; do { repeatChar = false; switch (ch) { case '(': Ordinality modifierOrdinality = Ordinality.One; AddTextToSequence(sequence, sb, fuzzyMatch); var subText = GetPatternGroup(chars).Trim(); bool inModifiers = true; while (inModifiers && chars.MoveNext()) { ch = chars.Current; switch (ch) { case '~': fuzzyMatch = !defaultFuzzyMatch; break; case '?': modifierOrdinality = Ordinality.ZeroOrOne; break; case '+': modifierOrdinality = Ordinality.OneOrMore; break; case '*': modifierOrdinality = Ordinality.ZeroOrMore; break; default: if (byte.TryParse(ch.ToString(), out byte num)) { maxMatches = num; } else { var patternMatcher = Parse(subText, fuzzyMatch, modifierOrdinality, maxMatches); sequence.PatternMatchers.Add(patternMatcher); // break out of modifier loop inModifiers = false; repeatChar = true; } break; } } if (inModifiers) { // paren was end of string. var patternMatcher = Parse(subText, fuzzyMatch, modifierOrdinality, maxMatches); sequence.PatternMatchers.Add(patternMatcher); } maxMatches = 16; fuzzyMatch = defaultFuzzyMatch; break; case '|': { AddTextToSequence(sequence, sb, fuzzyMatch); if (sequence.PatternMatchers.Count == 1) { ordinalityPatternMatcher.PatternMatchers.Add(sequence.PatternMatchers.Single()); } else { ordinalityPatternMatcher.PatternMatchers.Add(sequence); } sequence = new SequencePatternMatcher(); } break; default: sb.Append(ch); break; } } while (repeatChar); } AddTextToSequence(sequence, sb, fuzzyMatch); if (sequence.PatternMatchers.Any()) { if (sequence.PatternMatchers.Count == 1) { ordinalityPatternMatcher.PatternMatchers.Add(sequence.PatternMatchers.Single()); } else { ordinalityPatternMatcher.PatternMatchers.Add(sequence); } } // if this is a oneOf, maxMatches with a single pattern matcher, just the inner patternmatcher. PatternMatcher result = ordinalityPatternMatcher; if (ordinalityPatternMatcher.PatternMatchers.Count == 1 && ordinalityPatternMatcher.Ordinality == Ordinality.One) { result = ordinalityPatternMatcher.PatternMatchers.Single(); } // if it is a sequence with only one patternMatcher, just the inner patternmatcher if (result is SequencePatternMatcher spm && spm.PatternMatchers.Count == 1) { result = spm.PatternMatchers.Single(); } return(result); }
/// <summary> /// If a matcher in the sequence doesn't match, then it doesn't match /// </summary> /// <param name="context"></param> /// <param name="start"></param> /// <returns></returns> public override MatchResult Matches(MatchContext context, TokenEntity startToken, PatternMatcher nextPatternMatcher) { var tokenEntity = startToken; int start = startToken?.Start ?? 0; int end = 0; int minMatches = 1; int maxMatches = this.MaxMatches; switch (Ordinality) { case Ordinality.One: maxMatches = 1; break; case Ordinality.OneOrMore: break; case Ordinality.ZeroOrMore: minMatches = 0; break; case Ordinality.ZeroOrOne: minMatches = 0; maxMatches = 1; break; } int matched = 0; MatchResult matchResult = null; bool found; do { found = false; for (int iPattern = 0; iPattern < PatternMatchers.Count; iPattern++) { var patternMatcher = PatternMatchers[iPattern]; var result = patternMatcher.Matches(context, tokenEntity, nextPatternMatcher); if (result.Matched) { found = true; matched++; matchResult = result; end = Math.Max(result.End, end); tokenEntity = matchResult.NextToken; if (matched == maxMatches) { // then we are done; return(new MatchResult(true, this, tokenEntity, start, end) { NextPatternMatch = result.NextPatternMatch }); } break; } else { if (matchResult != null) { matchResult.NextPatternMatch = result.NextPatternMatch; } } } } while (found && tokenEntity != null); if (matched < minMatches) { // not matched. return(new MatchResult(false, this) { NextPatternMatch = matchResult?.NextPatternMatch }); } return(new MatchResult(true, this, tokenEntity, start, end) { NextPatternMatch = matchResult?.NextPatternMatch }); }
public override MatchResult Matches(MatchContext context, TokenEntity startToken, PatternMatcher nextPatternMatcher) { var tokenEntity = startToken; if (tokenEntity != null) { if (nextPatternMatcher != null) { MatchResult nextPatternMatch = nextPatternMatcher?.Matches(context, tokenEntity, null); if (nextPatternMatch.Matched && nextPatternMatch.NextToken != tokenEntity) { return(new MatchResult(false, this) { NextPatternMatch = nextPatternMatch }); } } if (!context.IsTokenMatched(tokenEntity)) { // if last child is a wildcard and it's end matches the last token's end // then we will merge the wildcards together. var previousToken = context.GetPrevTokenEntity(tokenEntity); var wildcardEntity = context.CurrentEntity.Children.FirstOrDefault(wildcard => wildcard.Type == this.entityType && wildcard.End == previousToken.End); if (wildcardEntity != null) { var newEntity = new LucyEntity() { Type = entityType, Start = wildcardEntity.Start, End = tokenEntity.End, Score = ((float)tokenEntity.End - wildcardEntity.Start) / context.Text.Length / 2, Text = context.Text.Substring(wildcardEntity.Start, tokenEntity.End - wildcardEntity.Start), Resolution = context.Text.Substring(wildcardEntity.Start, tokenEntity.End - wildcardEntity.Start), }; // remove old entity context.CurrentEntity.Children.Remove(wildcardEntity); // add new merged wildcard entity "joe" "smith" => "joe smith" context.AddToCurrentEntity(newEntity); } else { var newEntity = new LucyEntity() { Type = entityType, Start = tokenEntity.Start, End = tokenEntity.End, Score = ((float)tokenEntity.End - tokenEntity.Start) / context.Text.Length / 2, Text = context.Text.Substring(tokenEntity.Start, tokenEntity.End - tokenEntity.Start), Resolution = context.Text.Substring(tokenEntity.Start, tokenEntity.End - tokenEntity.Start) }; context.AddToCurrentEntity(newEntity); } return(new MatchResult(true, this, context.GetNextTokenEntity(tokenEntity), tokenEntity.Start, tokenEntity.End)); } } return(new MatchResult(false, this)); }
public override MatchResult Matches(MatchContext context, TokenEntity startToken, PatternMatcher nextPatterMatcher) { var tokenEntity = startToken; var matchResult = new MatchResult(false, this, tokenEntity); if (tokenEntity != null) { var entity = context.Entities.FirstOrDefault(le => le.Start == tokenEntity.Start && le.Type == EntityType); if (entity != null) { // add the matched entity to the children of the currentEntity. context.AddToCurrentEntity(entity); matchResult.Matched = true; matchResult.End = entity.End; matchResult.NextToken = context.GetFirstTokenEntity(entity.End); } } return(matchResult); }