Пример #1
0
        /// <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}) ");
        }
Пример #2
0
        /// <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);
            }
        }