2010-04-16 2 views
9

Я хочу использовать регулярное выражение так же, как string.Format. ПояснюЗаменить именованную группу в регулярном выражении со значением

у меня есть:

string pattern = "^(?<PREFIX>abc_)(?<ID>[0-9])+(?<POSTFIX>_def)$"; 
string input = "abc_123_def"; 
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase); 
string replacement = "456"; 
Console.WriteLine(regex.Replace(input, string.Format("${{PREFIX}}{0}${{POSTFIX}}", replacement))); 

Это работает, но я должен предоставить "вход" в regex.Replace. Мне этого не надо. Я хочу использовать шаблон для сопоставления, но также и для создания строк так же, как со строковым форматом, заменив именованную группу «ID» на значение. Это возможно?

Я ищу что-то вроде:

string pattern = "^(?<PREFIX>abc_)(?<ID>[0-9])+(?<POSTFIX>_def)$"; 
string result = ReplaceWithFormat(pattern, "ID", 999); 

Результат будет содержать "abc_999_def". Как это сделать?

+0

Это не совсем то, что вы ищете, но может иметь значение. Это, как правило, именованная строка.вместо индексации. http://haacked.com/archive/2009/01/04/fun-with-named-formats-string-parsing-and-edge-cases.aspx – chilltemp

ответ

12

Нет, нельзя использовать регулярное выражение без ввода ввода. Он должен иметь что-то, с чем можно работать, шаблон не может добавить какие-либо данные в результат, все должно происходить от ввода или замены.

Intead использования String.Format, вы можете использовать вид сзади и вид вперед, чтобы указать часть между «abc_» и «_def», и заменить его:

string result = Regex.Replace(input, @"(?<=abc_)\d+(?=_def)", "999"); 
+9

Почему downvote? Если вы не объясните, что вы считаете неправильным, оно не может улучшить ответ. – Guffa

+1

См. Ответ и комментарий пользователя1817787 –

+0

Лучшим ответом является не этот пост, а этот [один] (http://stackoverflow.com/a/13342795/2183236). – fharreau

13

Да, это возможно :

public static class RegexExtensions 
{ 
    public static string Replace(this string input, Regex regex, string groupName, string replacement) 
    { 
     return regex.Replace(input, m => 
     { 
      return ReplaceNamedGroup(input, groupName, replacement, m); 
     }); 
    } 

    private static string ReplaceNamedGroup(string input, string groupName, string replacement, Match m) 
    { 
     string capture = m.Value; 
     capture = capture.Remove(m.Groups[groupName].Index - m.Index, m.Groups[groupName].Length); 
     capture = capture.Insert(m.Groups[groupName].Index - m.Index, replacement); 
     return capture; 
    } 
} 

Использование:

Regex regex = new Regex("^(?<PREFIX>abc_)(?<ID>[0-9]+)(?<POSTFIX>_def)$"); 

string oldValue = "abc_123_def"; 
var result = oldValue.Replace(regex, "ID", "456"); 

Результат: abc_456_def

+2

-1. «Фу Гуффа» очень неуместен. –

+1

Не заставляй своих шучу шуметь. – Justin

+0

Нет, невозможно использовать регулярное выражение без ввода ввода. Вы вводите ввод в код в своем ответе, поэтому он не демонстрирует, что вы утверждаете. – Guffa

3

В user1817787 возникла проблема, и мне пришлось внести изменения в функцию ReplaceNamedGroup следующим образом.

private static string ReplaceNamedGroup(string input, string groupName, string replacement, Match m) 
{ 
    string capture = m.Value; 
    capture = capture.Remove(m.Groups[groupName].Index - m.Index, m.Groups[groupName].Length); 
    capture = capture.Insert(m.Groups[groupName].Index - m.Index, replacement); 
    return capture; 
} 
+0

выглядит так же ... – JobaDiniz

+1

@JobaDiniz Он отредактировал свой ответ, чтобы включить мой. См. Https://stackoverflow.com/posts/13342795/revisions – Justin

0

Другой отредактированная версия оригинального метод на @ user1817787, это один поддерживает несколько экземпляров названной группы (также включает в себя аналогичное исправление для одной @Justin отправило (возвращает результат с помощью {match.Index, матч .Length} вместо {0, input.Length}):

public static string ReplaceNamedGroup(
    string input, string groupName, string replacement, Match match) 
{ 
    var sb = new StringBuilder(input); 
    var matchStart = match.Index; 
    var matchLength = match.Length; 

    var captures = match.Groups[groupName].Captures.OfType<Capture>() 
     .OrderByDescending(c => c.Index); 

    foreach (var capt in captures) 
    { 
     if (capt == null) 
      continue; 

     matchLength += replacement.Length - capt.Length; 

     sb.Remove(capt.Index, capt.Length); 
     sb.Insert(capt.Index, replacement); 
    } 

    var end = matchStart + matchLength; 
    sb.Remove(end, sb.Length - end); 
    sb.Remove(0, matchStart); 

    return sb.ToString(); 
} 
+0

Если длина замещения отличается от длины захвата, она выкинет индексы после первого удаления/вставки. – user1620220

+0

@ user1620220 Я предположил замену одиночных символов одиночными символами, как в примере из вопроса 123 ==> 999. Например. для маскировки конфиденциальных данных. –

0

Простым решением является ссылка на замененные группы. Таким образом, префикс $1, а Postfix - $3.

Я не тестировал код, приведенный ниже, но должен работать похож на regEx я написал недавно:

string pattern = "^(?<PREFIX>abc_)(?<ID>[0-9])+(?<POSTFIX>_def)$"; 
string input = "abc_123_def"; 
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase); 
string replacement = String.Format("$1{0}$3", "456"); 
Console.WriteLine(regex.Replace(input, string.Format("${{PREFIX}}{0}${{POSTFIX}}", replacement))); 
1

Я укоротить ReplaceNamedGroup, по-прежнему поддерживает несколько захватов.

private static string ReplaceNamedGroup(string input, string groupName, string replacement, Match m) 
{ 
    string result = m.Value; 
    foreach (Capture cap in m.Groups[groupName]?.Captures) 
    { 
    result = result.Remove(cap.Index - m.Index, cap.Length); 
    result = result.Insert(cap.Index - m.Index, replacement); 
    } 
return result; 
} 
-1

Вы должны проверить документацию о RegEx заменить here

Я создал это для замены имени группы. Я не могу использовать это решение для всех имен групп, потому что у меня есть случай, когда не все выражения сгруппированы.

public static string ReplaceNamedGroup(this Regex regex, string input, string namedGroup, string value) 
    { 
     var replacement = Regex.Replace(regex.ToString(), 
      @"((?<GroupPrefix>\(\?)\<(?<GroupName>\w*)\>(?<Eval>.[^\)]+)(?<GroupPostfix>\)))", 
      @"${${GroupName}}").TrimStart('^').TrimEnd('$'); 
     replacement = replacement.Replace("${" + namedGroup + "}", value); 
     return Regex.Replace(input, regex.ToString(), replacement); 
    } 
Смежные вопросы