/// <summary> /// Create intersections of <paramref name="leftPattern"/> and <paramref name="rightPattern"/>. /// </summary> /// <param name="leftPattern"></param> /// <param name="rightPattern"></param> /// <returns>intersections</returns> public static IEnumerable <String> Intersections(string leftPattern, string rightPattern) { // Read in the tokens StructList24 <Token> leftTokens = new StructList24 <Token>(), rightTokens = new StructList24 <Token>(); Token.Enumerator leftEnumerator = new Token.Enumerator(leftPattern), rightEnumerator = new Token.Enumerator(rightPattern); while (leftEnumerator.MoveNext()) { leftTokens.Add(leftEnumerator.Current); } while (rightEnumerator.MoveNext()) { rightTokens.Add(rightEnumerator.Current); } // Queue of scenarios as index pairs and result so far. List <Line> queue = new List <Line>(); // List of already yielded strings HashSet <Line> visited = new HashSet <Line>(); // Queue the starting position Queue(queue, visited, 0, 0, null); // Process queue while (queue.Count > 0) { // Take indices from queue Line line = queue[queue.Count - 1]; int li = line.li, ri = line.ri; List <Token> result = line.tokens; queue.RemoveAt(queue.Count - 1); // Has more tokens bool leftHasMore = li < leftTokens.Count, rightHasMore = ri < rightTokens.Count; // End of tokens on both streams if (!leftHasMore && !rightHasMore) { // Print to string string pattern = Print(result); // yield result yield return(pattern); } // left still has tokens, right is at end else if (leftHasMore && !rightHasMore) { // Take token Token l = leftTokens[li]; // "*" and "**" matches against "" if (l == Token.Type.Star || l == Token.Type.StarStar) { Queue(queue, visited, li + 1, ri, result); } } // left is at end, right still has tokens else if (!leftHasMore && rightHasMore) { // Take token and type Token r = rightTokens[ri]; // "" matches against "*" and "**" if (r == Token.Type.Star || r == Token.Type.StarStar) { Queue(queue, visited, li, ri + 1, result); } } // left and right have tokens if (leftHasMore && rightHasMore) { // Take tokens Token l = leftTokens[li], r = rightTokens[ri]; // l == ** if (l == Token.Type.StarStar) { // Match one and more later CloneAndAppend(queue, visited, li, ri + 1, result, r); // r = *, r = ** if (r == Token.Type.Star || r == Token.Type.StarStar) { // Append(queue, visited, li + 1, ri, result, r); } else // r = x { // Match to nothing Queue(queue, visited, li + 1, ri, result); } // Next scenario continue; } // r == ** if (r == Token.Type.StarStar) { // Match one and more later CloneAndAppend(queue, visited, li + 1, ri, result, l); // l = *, l = ** if (l == Token.Type.Star || l == Token.Type.StarStar) { // Append(queue, visited, li, ri + 1, result, l); } else { // Match to nothing Queue(queue, visited, li, ri + 1, result); } // Next scenario continue; } // l == * if (l == Token.Type.Star) { // * & / if (r == Token.Type.Slash) { // Match / to nothing Queue(queue, visited, li + 1, ri, result); continue; } // Match to one and more later CloneAndAppend(queue, visited, li, ri + 1, result, r); // Match to r = * if (r == Token.Type.Star) { Append(queue, visited, li + 1, ri, result, r); } else { // Match to nothing Queue(queue, visited, li + 1, ri, result); } // Next scenario continue; } // r == * if (r == Token.Type.Star) { // / & * if (l == Token.Type.Slash) { // Match / to nothing Queue(queue, visited, li, ri + 1, result); continue; } // Match one, and more later CloneAndAppend(queue, visited, li + 1, ri, result, l); if (l == Token.Type.Star) { Append(queue, visited, li, ri + 1, result, l); } else { // Match to nothing Queue(queue, visited, li, ri + 1, result); } // Next scenario continue; } // l == ? if (l == Token.Type.QuestionMark) { // ? & / if (r == Token.Type.Slash) { continue; } // Downgrade '*' and '**' to '?' if (r.Kind == Token.Type.Star || r.Kind == Token.Type.StarStar) { r = Token.Type.QuestionMark; } // Append what ever is in right token Append(queue, visited, li + 1, ri + 1, result, r); // Next scenario continue; } // r == ? if (r == Token.Type.QuestionMark) { // / & ? if (l == Token.Type.Slash) { continue; } // Downgrade '*' and '**' to '?' if (l.Kind == Token.Type.Star || l.Kind == Token.Type.StarStar) { l = Token.Type.QuestionMark; } // Append what ever is in left token Append(queue, visited, li + 1, ri + 1, result, l); // Next scenario continue; } // l == r if (l == r) { // Append, move indices and queue. Append(queue, visited, li + 1, ri + 1, result, l); // Next scenario continue; } } } //Console.Write($" (visited={visited.Count}) "); }
/// <summary> /// Create union of <paramref name="leftPattern"/> and <paramref name="rightPattern"/>. /// </summary> /// <param name="leftPattern"></param> /// <param name="rightPattern"></param> /// <returns>union that contains <paramref name="leftPattern"/> and <paramref name="rightPattern"/>. May return broader union that minimal due to lack of expression capability to hold in a single pattern string.</returns> public static string Union(string leftPattern, string rightPattern) { // Same pattern if (leftPattern == rightPattern) { return(leftPattern); } // Read in the tokens StructList24 <Token> leftTokens = new StructList24 <Token>(), rightTokens = new StructList24 <Token>(); Token.Enumerator leftEnumerator = new Token.Enumerator(leftPattern), rightEnumerator = new Token.Enumerator(rightPattern); while (leftEnumerator.MoveNext()) { leftTokens.Add(leftEnumerator.Current); } while (rightEnumerator.MoveNext()) { rightTokens.Add(rightEnumerator.Current); } // Queue of scenarios as index pairs and result so far. List <Line> queue = new List <Line>(); // List of already yielded strings HashSet <Line> visited = new HashSet <Line>(); // Queue the starting position Queue(queue, visited, 0, 0, null); // Final result List <Token> finalresult = null; int finalscore = int.MinValue; // Process queue while (queue.Count > 0) { // Take indices from queue Line line = queue[queue.Count - 1]; int li = line.li, ri = line.ri; List <Token> result = line.tokens; queue.RemoveAt(queue.Count - 1); // Has more tokens bool leftHasMore = li < leftTokens.Count, rightHasMore = ri < rightTokens.Count; // l = Left input, r = right input, _ = last in result Token l = leftHasMore ? leftTokens[li] : (Token)Token.Type.None, r = rightHasMore ? rightTokens[ri] : (Token)Token.Type.None, _ = result == null || result.Count == 0 ? (Token)Token.Type.None : result[result.Count - 1]; // End of tokens on both streams if (!leftHasMore && !rightHasMore) { int score = Score(result); if (score > finalscore) { finalresult = result; finalscore = score; } continue; } // left or right have tokens if (leftHasMore || rightHasMore) { // l == ** if (l == Token.Type.StarStar) { if (_ == Token.Type.StarStar) { Queue(queue, visited, li + 1, ri, result); } else { Append(queue, visited, li + 1, ri, result, l); } continue; } // r == ** if (r == Token.Type.StarStar) { if (_ == Token.Type.StarStar) { Queue(queue, visited, li, ri + 1, result); } else { Append(queue, visited, li, ri + 1, result, r); } continue; } // l == * if (l == Token.Type.Star) { if (_ == Token.Type.Star || _ == Token.Type.StarStar) { Queue(queue, visited, li + 1, ri, result); } else { Append(queue, visited, li + 1, ri, result, l); } continue; } // r == * if (r == Token.Type.Star) { if (_ == Token.Type.Star || _ == Token.Type.StarStar) { Queue(queue, visited, li, ri + 1, result); } else { Append(queue, visited, li, ri + 1, result, r); } continue; } // l == r if (l == r) { Append(queue, visited, li + 1, ri + 1, result, l); continue; } // l == ? && r == c if (l == Token.Type.QuestionMark && r.Kind == Token.Type.Char) { Append(queue, visited, li + 1, ri + 1, result, l); continue; } // l == c && r == ? if (l.Kind == Token.Type.Char && r == Token.Type.QuestionMark) { Append(queue, visited, li + 1, ri + 1, result, l); continue; } // l == c || r == c if (l.Kind == Token.Type.Char || r.Kind == Token.Type.Char) { // Add ? if (l.Kind == Token.Type.Char && r.Kind == Token.Type.Char) { CloneAndAppend(queue, visited, li + 1, ri + 1, result, Token.Type.QuestionMark); } // Add * if (_ != Token.Type.Star && _ != Token.Type.StarStar) { if (l.Kind == Token.Type.Char) { CloneAndAppend(queue, visited, li + 1, ri, result, Token.Type.Star); } if (r.Kind == Token.Type.Char) { Append(queue, visited, li, ri + 1, result, Token.Type.Star); } } else // Use previous * { if (l.Kind == Token.Type.Char) { CloneAndAppend(queue, visited, li + 1, ri, result, Token.Type.None); } if (r.Kind == Token.Type.Char) { Queue(queue, visited, li, ri + 1, result); } } continue; } { // Replace * with ** if (_ == Token.Type.Star) { result[result.Count - 1] = Token.Type.StarStar; if (l != Token.Type.None) { CloneAndAppend(queue, visited, li + 1, ri, result, Token.Type.None); } if (r != Token.Type.None) { Queue(queue, visited, li, ri + 1, result); } } // Add ** else if (_ != Token.Type.StarStar) { if (l != Token.Type.None) { CloneAndAppend(queue, visited, li + 1, ri, result, Token.Type.StarStar); } if (r != Token.Type.None) { Append(queue, visited, li, ri + 1, result, Token.Type.StarStar); } } else // Use previous ** { if (l != Token.Type.None) { CloneAndAppend(queue, visited, li + 1, ri, result, Token.Type.None); } if (r != Token.Type.None) { Queue(queue, visited, li, ri + 1, result); } } } } } //Console.Write($" (visited={visited.Count}) "); return(Print(finalresult)); // Heuristic score int Score(List <Token> result) { if (result == null) { return(int.MinValue); } int x = 0; foreach (Token t in result) { if (t.Kind == Token.Type.Char) { x += 256; } else if (t.Kind == Token.Type.QuestionMark) { x += 16; } else if (t.Kind == Token.Type.Slash) { x += 1024; } else if (t.Kind == Token.Type.Star) { x -= 4; } else if (t.Kind == Token.Type.StarStar) { x -= 16; } } return(x); } }