有没有办法使用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转储并按字母顺序对现有的INDEXES进行排序,示例代码:
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*)+",
答案 0 :(得分:2)
单独使用正则表达式无法做到这一点。但是您可以使用回调函数并利用.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 ...,
块。这会按名称对整个块进行排序。然后我们可以简单地将块连接在一起,添加之前使用的空白分隔符并返回它们。
答案 1 :(得分:0)
不确定我是否完全理解这个问题,但确实将foreach改为:
foreach (Match match in keys.Cast<Match>().OrderBy(m => m.Value))
做你想做的事吗?