生成所有符合正则表达式的匹配项

3

为了让用户进行选择,我想提供一个数字列表,这个列表需要匹配给定的正则表达式。这个正则表达式非常简单,它只能看起来像这样 123[0-9][0-9] 或者 [4-9]34.2

我发现 Fare (https://github.com/moodmosaic/Fare) 可以帮助完成这个任务。请参考下面的示例:

string pattern = "123[0-9][0-9]";
var xeger = new Xeger(pattern);
var match = xeger.Generate(); //match is e.g. "12349"

不幸的是,Fare-lib只给出了一个可能的匹配项,但并没有列出字符串可以有的所有100个可能组合。

如果您认为在这种情况下正则表达式不是一个好主意,并且更愿意建议使用for-loop实现替换字符,那么我也会采用这种方式,但目前我不知道如何做?也许一个递归函数会很聪明?


你会从 [0-9]+ 期望什么? - L.B
抱歉,我不确定您的意思。123[0-9][0-9]表示12300、12310、12311等。 - Kai
但是 [0-9]+ 会产生无限的结果。如果您知道模式并且它像您的示例一样是有限制的,则不需要正则表达式。嵌套两个循环就足够了 for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { } } - L.B
我最初认为只需要两个嵌套循环就可以了,但是如何以清晰的方式实现呢? - Kai
1
什么是困难?var list = (from i in Enumerable.Range(0, 10) from j in Enumerable.Range(6, 4) select "1" + i + "3" + j + "5").ToList(); - L.B
显示剩余3条评论
2个回答

2
我宁愿自己写代码实现,也不想使用库。下面这段代码可以实现你想要达到的效果。
 private static Regex regexRegex = new Regex("\\[(?<From>\\d)-(?<To>\\d)]", RegexOptions.Compiled);

    private static IEnumerable<string> GetStringsForRegex(string pattern)
    {
        var strings = Enumerable.Repeat("", 1);
        var lastIndex = 0;
        foreach (Match m in regexRegex.Matches(pattern))
        {
            if (m.Index > lastIndex)
            {
                var capturedLastIndex = lastIndex;
                strings = strings.Select(s => s + pattern.Substring(capturedLastIndex, m.Index - capturedLastIndex));
            }
            int from = int.Parse(m.Groups["From"].Value);
            int to = int.Parse(m.Groups["To"].Value);
            if (from > to)
            {
                throw new InvalidOperationException();
            }
            strings = strings.SelectMany(s => Enumerable.Range(from, to - from + 1), (s, i) => s + i.ToString());
            lastIndex = m.Index + m.Length;
        }
        if (lastIndex < pattern.Length)
        {
             var capturedLastIndex = lastIndex;
             strings = strings.Select(s => s + pattern.Substring(capturedLastIndex));
        }
        return strings;
    }

基本上,代码构建了正则表达式模式的所有解决方案。它甚至按字母顺序计算它们。

注意capturedLastIndex变量。由于编译器会捕获lastIndex变量,导致结果不正确,因此需要该变量。


抱歉,GetStringsForRegex(@“1 \ d3 [0-9] [0-9]”)无法工作。 - L.B
很抱歉,但是无论是对于模式“1234.”还是“1234[0-9]”,都不起作用。 - Kai
@L.B 嗯,你最初写的是“它只能看起来像这样123 [0-9] [0-9]或[4-9] 34.2”。没有提到\d。(而且您可以通过将.视为[0-9]来添加.支持。) - Raymond Chen
@RaymondChen 我之前没有写过任何东西 :) 重新阅读问题、评论和答案。 - L.B
是的,如果我用[0-9]替换.,它几乎可以正常工作。如果模式是123 [0-9] [0-9],我会得到像“240 [0-9] 00”这样的结果。 - Kai
显示剩余6条评论

1
这是我的代码,目前对我有效。它不太通用,只适用于字符串中的两种可能表达式,但它能正常工作 ;)
        List<string> possibleMatches = new List<string>();

        string expression = "123?[3-9]" //this is an example

        if (expression.Contains("?") || expression.Contains("["))
        {               
            int count = expression.Count(f => f == '?');
            count += expression.Count(f => f == '[');
            if (count <= 2)
            {
                string pattern = expression.Replace('*', '.').Replace('?', '.');
                pattern = pattern.Replace(".", "[0-9]"); 

                int pos1 = pattern.IndexOf('[');
                int start1 = Convert.ToInt32(pattern[pos1 + 1].ToString());
                int end1 = Convert.ToInt32(pattern[pos1 + 3].ToString());

                int pos2 = 0;
                int start2, end2 = 0;
                if (count > 1)
                {
                    pos2 = pattern.IndexOf('[', pos1);
                    start2 = Convert.ToInt32(pattern[pos2 + 1].ToString());
                    end2 = Convert.ToInt32(pattern[pos2 + 3].ToString());

                    pattern = pattern.Remove(pos1, "[0-9]".Length);
                    pattern = pattern.Remove(pos2, "[0-9]".Length);

                    string copy = pattern;
                    for (int i = start1; i <= end1; i++)
                    {
                        copy = pattern.Insert(pos1, i.ToString());
                        for (int y = start2; y <= end2; y++)
                        {
                            possibleMatches.Add(copy.Insert(pos2, y.ToString()));
                        }
                    }
                }
                else
                {
                    pattern = pattern.Remove(pos1, "[0-9]".Length);

                    for (int i = start1; i <= end1; i++)
                    {
                        possibleMatches.Add(pattern.Insert(pos1, i.ToString()));
                    }
                }
            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接