C# сортировать и возвращать регулярное выражение.спички
Существует ли какой-либо способ использования регулярных выражений.Совпадения, чтобы найти и записать обратно совпадающие значения, но в другом (алфавитном) порядке?
На данный момент у меня есть что-то вроде:
var pattern = @"(KEY `[w]+?` (`.*`*))";
var keys = Regex.Matches(line, pattern);
Console.WriteLine("nn");
foreach (Match match in keys)
{
Console.WriteLine(match.Index + " = " + match.Value.Replace("n", "").Trim());
}
Но что мне действительно нужно, так это сесть за стол.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 solution дал мне основы, которые я мог бы использовать, чтобы двигаться дальше. К сожалению, я не очень хорошо разбираюсь в регулярных выражениях, но в итоге у меня получился код, который я верить можно еще лучше:
...
//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*)+",
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 ...,
. Это сортирует полные блоки по их названиям. Затем мы можем просто объединить блоки, добавить разделитель пробелов, который использовался ранее, и вернуть их.