C#对Regex.matches进行排序并放回

C#对Regex.matches进行排序并放回,c#,mysql,regex,sorting,asp.net-4.0,C#,Mysql,Regex,Sorting,Asp.net 4.0,是否有任何方法可以使用RegEx.Matches查找和写回匹配的值,但顺序不同(字母顺序) 现在我有一些类似的东西: var pattern = @"(KEY `[\w]+?` \(`.*`*\))"; var keys = Regex.Matches(line, pattern); Console.WriteLine("\n\n"); foreach (Match match in keys) { Console.WriteLine(match.Index + " = " + mat

是否有任何方法可以使用RegEx.Matches查找和写回匹配的值,但顺序不同(字母顺序)

现在我有一些类似的东西:

var pattern = @"(KEY `[\w]+?` \(`.*`*\))";
var keys = Regex.Matches(line, pattern);

Console.WriteLine("\n\n");
foreach (Match match in keys)
{
    Console.WriteLine(match.Index + " = " + match.Value.Replace("\n", "").Trim());
}
但我真正需要的是获取table.sql dump并按字母顺序对现有索引进行排序,示例代码:

line = "...PRIMARY KEY (`communication_auto`),\n  KEY `idx_current` (`current`),\n  KEY `idx_communication` (`communication_id`,`current`),\n  KEY `idx_volunteer` (`volunteer_id`,`current`),\n  KEY `idx_template` (`template_id`,`current`)\n);"
谢谢 J

更新: 谢谢,m.buettner解决方案给了我一些基础知识,我可以用它们继续前进。遗憾的是,我不太擅长正则表达式,但我最终得到了我认为仍然可以改进的代码:

...
//sort INDEXES definitions alphabetically
if (line.Contains("  KEY `")) line = Regex.Replace(
    line,
    @"[ ]+(KEY `[\w]+` \([\w`,]+\),?\s*)+",
    ReplaceCallbackLinq
);

static string ReplaceCallbackLinq(Match match) 
{
    var result = String.Join(",\n  ",
        from Capture item in match.Groups[1].Captures
        orderby item.Value.Trim()
        select item.Value.Trim().Replace("),", ")")
    );
    return "  " + result + "\n";
}

更新: 还有一种情况是,索引字段长度超过255个字符,mysql将索引修剪为255个字符,并按如下方式写入:

KEY `idx3` (`app_property_definition_id`,`value`(255),`audit_current`),
因此,为了匹配这种情况,我必须更改一些代码: 在ReplaceCallbackLinq中:

select item.Value.Trim().Replace("`),", "`)")
以及正则表达式的定义:

@"[ ]+(KEY `[\w]+` \([\w`(\(255\)),]+\),?\s*)+",

不确定我是否完全理解该问题,但将foreach更改为:

foreach (Match match in keys.Cast<Match>().OrderBy(m => m.Value))
foreach(匹配keys.Cast().OrderBy(m=>m.Value))

做你想做的吗?

单用正则表达式无法做到这一点。但是您可以使用回调函数,并利用.NET的独特功能,用同一个捕获组捕获多个对象。这样可以避免使用
匹配项
并自己写回所有内容。相反,您可以使用内置的
Replace
功能。下面的示例只是对
短语进行排序,并将它们放回原样(因此它只对SQL语句中的短语进行排序)。如果您想要不同的输出,可以通过捕获模式的不同部分并在最后调整
Join
操作来轻松实现

首先,我们需要一个匹配计算器来传递回调:

MatchEvaluator evaluator = new MatchEvaluator(ReplaceCallback);
然后,我们编写一个正则表达式,一次匹配整个索引集,在一个捕获组中捕获索引名。我们将其放入
Replace
的重载中,该重载需要一个求值器:

output = Regex.Replace(
    input,
    @"(KEY `([\w]+)` \(`[^`]*`(?:,`[^`]*`)*\),?\s*)+",
    evaluator
);
现在在大多数语言中,这是没有用的,因为由于重复,捕获组1总是只包含捕获的第一个或最后一个内容(与捕获组2相同)。但幸运的是,您使用的是C#,而.NET的正则表达式引擎只是一个强大的野兽。让我们看看回调函数以及如何使用多个捕获:

static string ReplaceCallback(Match match)
{
    int captureCount = match.Groups[1].Captures.Count;
    string[] indexNameArray = new string[captureCount];
    string[] keyBlockArray = new string[captureCount];
    for (int i = 0; i < captureCount; i++)
    {
        keyBlockArray[i] = match.Groups[1].Captures[i].Value;
        indexNameArray[i] = match.Groups[2].Captures[i].Value;
    }
    Array.Sort(indexNameArray, keyBlockArray);
    return String.Join("\n  ", keyBlockArray);
}
静态字符串替换回调(匹配)
{
int captureCount=match.Groups[1].Captures.Count;
string[]indexNameArray=新字符串[captureCount];
string[]keyBlockArray=新字符串[captureCount];
对于(int i=0;i

match.Groups[i].Captures
允许我们访问单个组的多个捕获。由于这些对象是
Capture
对象,目前似乎并不真正有用,因此我们根据它们的值构建两个字符串数组。然后我们使用
Array.Sort
,它根据一个数组(被认为是键)的值对两个数组进行排序。作为“键”,我们使用表名的捕获。作为“值”,我们使用一个完整的
键…,
块的完整捕获。这将按名称对整个块进行排序。然后我们可以简单地将块连接在一起,添加以前使用的空格分隔符并返回它们。

谢谢,也许我不够清楚。你们的代码解决了一半的问题,第二部分是如何以新的顺序写回。谢谢,这个解决方案给了我一些基础知识,我可以用它继续前进。遗憾的是,我不太擅长正则表达式,但我最终得到了我认为仍然可以改进的代码: