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

#c# #asp.net #regex

#c# #asp.net #регулярное выражение

Вопрос:

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

Например, в строке

 @1 is having lunch with @10 @11
 

Я хотел бы заменить «@1», «@10» и «@11» соответствующими значениями, как указано ниже.

 "@1" replace with "@bob"
"@10" replace with "@joe"
"@11" replace with "@sam"
 

Таким образом, конечный результат будет выглядеть так

 "@bob is having lunch with @joe @sam"
 

Попытки с

 String.Replace("@1", "@bob")
 

приводит к следующему

 @bob is having lunch with @bob0 @bob1
 

Есть мысли о том, каким может быть решение?

Комментарии:

1. Вы ограничены форматом @<число>? Кроме того, вы определяете, что это за числа?

2. Я бы рекомендовал, чтобы ответы не основывались на предположении, что после будет пробел @1 . Обычно код, который выполняет подобные действия, не должен знать или заботиться о содержимом строки, в которой производятся замены. На мой взгляд, это должно работать, независимо от того, следует ли @1 за пробелом, запятой, точкой, точкой с запятой или другой пунктуацией. Я думаю, справедливым предположением было бы то, что за «параметрами» ( @1 , @10 , и @11 ) не сразу следуют какие-либо альфа-символы, хотя это было бы для подтверждения запрашивающим.

Ответ №1:

Я бы предпочел более декларативный способ сделать это. Что, если будут другие замены, например @2 , изменение на luke ? Вам придется изменить код (добавить еще Replace один вызов).

Мое предложение с объявлениями замен:

 string input = "@1 is having lunch with @10 @11";
var rules = new Dictionary<string,string>() 
{
    { "@1", "@bob" },
    { "@10", "@joe" },
    { "@11", "@sam"}
};

string output = Regex.Replace(input, 
                              @"@d ", 
                              match => rules[match.Value]);
 

Объяснение:

Регулярное выражение ищет шаблон @d , за которым @ следует одна или несколько цифр. И заменяет это совпадение благодаря MatchEvaluator правильной записи из rules словаря, где ключом является само значение соответствия.

Комментарии:

1. Правила должны применяться в порядке («@11 -> @sam» перед «@1 -> @bob»), и словарь не сохраняет порядок. Кажется, что вы должны использовать List<Tuple<String, String>> или похожие

2. @DmitryBychenko нет необходимости применять какой-либо порядок. В отличие от повторяющихся String.Replace вызовов, это регулярное выражение будет точно соответствовать каждому заполнителю и заменит их за один раз

3. Нет необходимости проверять группировки, match.Value уже содержит текст-заполнитель

Ответ №2:

Предполагая, что все заполнители начинаются с @ и содержат только цифры, вы можете использовать перегрузку Regex.Replace, которая принимает делегат MatchEvaluator для выбора значения замены из словаря:

 var regex = new Regex(@"@d ");

var dict = new Dictionary<string, string>
{
    {"@1","@bob"},
    {"@10","@joe"},
    {"@11","@sam"},
};

var input = "@1 is having lunch with @10 @11";
var result=regex.Replace(input, m => dict[m.Value]);
 

Результатом будет "@bob is having lunch with @joe @sam"

Есть несколько преимуществ по сравнению с несколькими String.Replace вызовами:

  1. Код более лаконичный, для произвольного количества заполнителей
  2. Вы избегаете ошибок из-за порядка замен (например @11 , должны быть раньше @1 )
  3. Это быстрее, потому что вам не нужно искать и заменять заполнители несколько раз
  4. Он не создает временные строки для каждого параметра. Это может быть проблемой для серверных приложений, поскольку большое количество потерянных строк будет оказывать давление на сборщик мусора

Причина преимуществ 3-4 заключается в том, что регулярное выражение будет анализировать входные данные и создавать внутреннее представление, содержащее индексы для любого соответствия. Когда приходит время для создания окончательной строки, он использует StringBuilder для чтения символов из исходной строки, но подставляет заменяющие значения при обнаружении совпадения.

Комментарии:

1. Это кажется более элегантным решением и до сих пор работало с имеющимися у нас тестовыми данными. Спасибо.

Ответ №3:

Начните с самого большого (читай, самого длинного) числа, например, @11 и @10, а затем замените @1.

 string finalstring = mystring.Replace("@11", "@sam")
                             .Replace("@10", "@joe")
                             .Replace("@1", "@bob");
 

Комментарии:

1. Я думаю, что важно сначала сделать акцент на больших числах.

2. @Aelphaeis: Спасибо. Выполнено.

3. Вы должны начать с самого длинного, а не с «самого большого» числа ( @2 больше, чем @10 ?). Фактический порядок параметров не имеет значения

Ответ №4:

Заставьте ваше регулярное выражение искать строку @1_

Пробел после гарантирует, что он получит только число @1.