C# 返回与正则表达式匹配的有限集

C# 返回与正则表达式匹配的有限集,c#,regex,algorithm,C#,Regex,Algorithm,类似于,我正在尝试获得一个与特定正则表达式匹配的集合。我的答案可能适合您。如果正则表达式不涉及 任何*操作(因此它识别的语言是有限的),都应该很容易 将正则表达式重写为BNF语法,然后进行自下而上的分析 与每个非终结符符号对应的有限集,直到到达 开始符号,此时您就完成了。基本上,您需要解析正则表达式,然后输出变量,而不是在遍历解析表达式时读取输入 我已经破解了下面的程序,可以实现非常简单的正则表达式(只支持使用的可选选项、使用*的迭代、使用()的分组和使用\的转义)。请注意,迭代只需进行0-5次

类似于,我正在尝试获得一个与特定正则表达式匹配的集合。

我的答案可能适合您。如果正则表达式不涉及 任何*操作(因此它识别的语言是有限的),都应该很容易 将正则表达式重写为BNF语法,然后进行自下而上的分析 与每个非终结符符号对应的有限集,直到到达
开始符号,此时您就完成了。

基本上,您需要解析正则表达式,然后输出变量,而不是在遍历解析表达式时读取输入

我已经破解了下面的程序,可以实现非常简单的正则表达式(只支持使用
的可选选项、使用
*
的迭代、使用
()
的分组和使用
\
的转义)。请注意,迭代只需进行0-5次,转换为可能的无限次迭代,留给读者作为练习;-)

我使用了一个简单的递归下降解析器在内存中构建了一个抽象语法树;这棵树在最后走了,所有可能的集合都被建立起来了。这个解决方案可能根本不是最优的,但它是有效的。享受:

public class TestPrg
{
    static void Main()
    {
        var expression = new RegexParser("a(b|c)*d").Parse();

        foreach (var item in expression.Generate())
        {
            Console.WriteLine(item);
        }
    }
}

public static class EnumerableExtensions
{
    // Build a Cartesian product of a sequence of sequences
    // Code by Eric Lippert, copied from <http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx>
    public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
    {
        IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
        return sequences.Aggregate(
            emptyProduct,
            (accumulator, sequence) =>
            from accseq in accumulator
            from item in sequence
            select accseq.Concat(new[] { item }));
    }
}

public class RegexParser
{
    private const char EOF = '\x0000';
    private readonly string str;
    private char curr;
    private int pos;

    public RegexParser(string s)
    {
        str = s;
    }

    public RegExpression Parse()
    {
        pos = -1;
        Read();
        return ParseExpression();
    }

    private void Read()
    {
        ++pos;
        curr = pos < str.Length ? str[pos] : EOF;
    }

    private RegExpression ParseExpression()
    {
        var term = ParseTerm();
        if (curr == '|')
        {
            Read();
            var secondExpr = ParseExpression();
            return new Variants(term, secondExpr);
        }
        else
        {
            return term;
        }
    }

    private RegExpression ParseTerm()
    {
        var factor = ParseFactor();
        if (curr != '|' && curr != '+' && curr != '*' && curr != ')' && curr != EOF)
        {
            var secondTerm = ParseTerm();
            return new Concatenation(factor, secondTerm);
        }
        else
        {
            return factor;
        }
    }

    private RegExpression ParseFactor()
    {
        var element = ParseElement();
        if (curr == '*')
        {
            Read();
            return new Repeat(element);
        }
        else
        {
            return element;
        }
    }

    private RegExpression ParseElement()
    {
        switch (curr)
        {
            case '(':
                Read();
                var expr = ParseExpression();
                if (curr != ')') throw new FormatException("Closing paren expected");
                Read();
                return expr;

            case '\\':
                Read();
                var escapedChar = curr;
                Read();
                return new Literal(escapedChar);

            default:
                var literal = curr;
                Read();
                return new Literal(literal);
        }
    }
}

public abstract class RegExpression
{
    protected static IEnumerable<RegExpression> Merge<T>(RegExpression head, RegExpression tail, Func<T, IEnumerable<RegExpression>> selector)
        where T : RegExpression
    {
        var other = tail as T;
        if (other != null)
        {
            return new[] { head }.Concat(selector(other));
        }
        else
        {
            return new[] { head, tail };
        }
    }

    public abstract IEnumerable<string> Generate();
}

public class Variants : RegExpression
{
    public IEnumerable<RegExpression> Subexpressions { get; private set; }

    public Variants(RegExpression term, RegExpression rest)
    {
        Subexpressions = Merge<Variants>(term, rest, c => c.Subexpressions);
    }

    public override IEnumerable<string> Generate()
    {
        return Subexpressions.SelectMany(sub => sub.Generate());
    }
}

public class Concatenation : RegExpression
{
    public IEnumerable<RegExpression> Subexpressions { get; private set; }

    public Concatenation(RegExpression factor, RegExpression rest)
    {
        Subexpressions = Merge<Concatenation>(factor, rest, c => c.Subexpressions);
    }

    public override IEnumerable<string> Generate()
    {
        foreach (var variant in Subexpressions.Select(sub => sub.Generate()).CartesianProduct())
        {
            var builder = new StringBuilder();
            foreach (var item in variant) builder.Append(item);
            yield return builder.ToString();
        }
    }
}

public class Repeat : RegExpression
{
    public RegExpression Expr { get; private set; }

    public Repeat(RegExpression expr)
    {
        Expr = expr;
    }

    public override IEnumerable<string> Generate()
    {
        foreach (var subexpr in Expr.Generate())
        {
            for (int cnt = 0; cnt < 5; ++cnt)
            {
                var builder = new StringBuilder(subexpr.Length * cnt);
                for (int i = 0; i < cnt; ++i) builder.Append(subexpr);
                yield return builder.ToString();
            }
        }
    }
}

public class Literal : RegExpression
{
    public char Ch { get; private set; }

    public Literal(char c)
    {
        Ch = c;
    }

    public override IEnumerable<string> Generate()
    {
        yield return new string(Ch, 1);
    }
}
公共类TestPrg
{
静态void Main()
{
var expression=new RegexParser(“a(b | c)*d”).Parse();
foreach(表达式.Generate()中的变量项)
{
控制台写入线(项目);
}
}
}
公共静态类EnumerableExtensions
{
//构建序列的笛卡尔乘积
//代码由Eric Lippert编写,复制自
公共静态IEnumerable CartesianProduct(此IEnumerable序列)
{
IEnumerable emptyProduct=new[]{Enumerable.Empty()};
返回序列.聚合(
空产品,
(累加器,顺序)=>
来自蓄能器中的accseq
按顺序从项目开始
选择accseq.Concat(新[]{item}));
}
}
公共类RegexParser
{
私有常量字符EOF='\x0000';
私有只读字符串str;
私家车;
私人国际邮政局;
公共RegexParser(字符串s)
{
str=s;
}
公共正则表达式解析()
{
pos=-1;
Read();
返回ParseExpression();
}
私有void Read()
{
++pos;
curr=pos