C# 排序并放回 Regex.matches

标签 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 + " = " + match.Value.Replace("\n", "").Trim());
}

但我真正需要的是获取 table.sql 转储并按字母顺序对现有索引进行排序,示例代码:

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);"

谢谢 杰


更新: 谢谢,m.buettner 解决方案为我提供了可以继续前进的基础知识。遗憾的是,我不太擅长 RegEx,但我最终得到了我认为仍然可以改进的代码:

...
//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*)+",

最佳答案

这不能单独使用正则表达式来完成。但是您可以使用回调函数并利用 .NET 的独特功能,即使用同一捕获组捕获多个事物。这样您就可以避免使用 Matches 并自己写回所有内容。相反,您可以使用内置的Replace 功能。我下面的示例简单地对 KEY 短语进行排序并将它们放回原样(因此它除了在 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);
}

match.Groups[i].Captures 让我们可以访问单个组的多个捕获。由于这些是 Capture 对象,目前看起来并不是很有用,我们从它们的值构建两个字符串数组。然后我们使用 Array.Sort 根据一个数组的值(被视为键)对两个数组进行排序。作为“键”,我们使用表名的捕获。作为“值”,我们使用一个完整的 KEY ..., block 的完整捕获。这将按名称对完整 block 进行排序。然后我们可以简单地将 block 连接在一起,添加之前使用的空白分隔符并返回它们。

关于C# 排序并放回 Regex.matches,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13317864/

相关文章:

c# - 如何将带有 .MDF 文件 (Sql 2008) 的现有 ASP.NET MVC 3 项目迁移到 Windows Azure 模拟器(使用 SQL Azure)

sql - 我如何正确地为基于 SQL 的数据库中的数据建模,这些数据库有一些共同的列,但也有一些独特的列?

Python 正则表达式 - 在搜索过程中忽略序列

c# - ASP.NET CORE MVC 选择标签助手 - 如何在不使用 ModelView 的情况下设置所选值

c# - 如何使用 C# 获取 Msmq 的访问控制列表

mysql - 在mysql中从数据库创建转储文件

mysql - 选择其他表中具有匹配列的行

regex - 如何使用 sprintf 创建一个正则表达式来匹配文本文件中的 1 个但不超过 N 个连续单词?

python - 正则表达式:当字符串包含正则表达式模式的一部分时匹配字符串的一部分

c# - 无法从字符转换为字符串