2009-08-05 3 views
22

У меня есть строка, на которой мне нужно сделать некоторые замены. У меня есть Dictionary<string, string>, где я определил пары замены поиска. Я создал следующие методы расширения для выполнения этой операции:C# String заменить на словарь

public static string Replace(this string str, Dictionary<string, string> dict) 
{ 
    StringBuilder sb = new StringBuilder(str); 

    return sb.Replace(dict).ToString(); 
} 

public static StringBuild Replace(this StringBuilder sb, 
    Dictionary<string, string> dict) 
{ 
    foreach (KeyValuePair<string, string> replacement in dict) 
    { 
     sb.Replace(replacement.Key, replacement.Value); 
    } 

    return sb; 
} 

Есть ли лучший способ сделать это?

ответ

38

Если данные лексемы (т.е. "Dear $ имя $, по состоянию на $ Date $ Ваш баланс $ сумма $"), то Regex может быть полезным:

static readonly Regex re = new Regex(@"\$(\w+)\$", RegexOptions.Compiled); 
static void Main() { 
    string input = @"Dear $name$, as of $date$ your balance is $amount$"; 

    var args = new Dictionary<string, string>(
     StringComparer.OrdinalIgnoreCase) { 
      {"name", "Mr Smith"}, 
      {"date", "05 Aug 2009"}, 
      {"amount", "GBP200"} 
     }; 
    string output = re.Replace(input, match => args[match.Groups[1].Value]); 
} 

Однако, без чего-то вроде это, я ожидаю, что ваш цикл Replace, вероятно, примерно столько, сколько вы можете сделать, не дожидаясь крайних длин. Если он не обозначен, возможно, его профиль; Replace на самом деле проблема?

+0

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

+0

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

+1

Это вызовет исключение, если ключ не найден. – Axel

9

Кажется разумным для меня, кроме одного: он чувствителен к порядку. Например, возьмем входной строки «$ х $ у» и замены словаря:

"$x" => "$y" 
"$y" => "foo" 

Результаты замены являются либо «Foo Foo» или «$ у Foo» в зависимости от замены выполняется первым.

Вы можете управлять заказом, используя вместо этого List<KeyValuePair<string, string>>. Альтернативой является прогулка по строке, чтобы вы не потребляли замены при последующих операциях замены. Это, вероятно, будет намного сложнее.

12

ли это с Linq:

var newstr = dict.Aggregate(str, (current, value) => 
    current.Replace(value.Key, value.Value)); 

ДИКТ Ваш поиск замены пар определенных словарь объекта.

str - это ваша строка, в которой вам нужно выполнить некоторые замены.

+0

+1 Я использовал regex в прошлом, но это отлично поработало для меня. – clairestreb

4

Вот слегка повторно факторизуется версия @ большой ответ Марка, чтобы сделать функциональные возможности, доступные в качестве метода расширения для Regex:

static void Main() 
{ 
    string input = @"Dear $name$, as of $date$ your balance is $amount$"; 
    var args = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); 
    args.Add("name", "Mr Smith"); 
    args.Add("date", "05 Aug 2009"); 
    args.Add("amount", "GBP200"); 

    Regex re = new Regex(@"\$(\w+)\$", RegexOptions.Compiled); 
    string output = re.replaceTokens(input, args); 

    // spot the LinqPad user // output.Dump(); 
} 

public static class ReplaceTokensUsingDictionary 
{ 
    public static string replaceTokens(this Regex re, string input, IDictionary<string, string> args) 
    { 
     return re.Replace(input, match => args[match.Groups[1].Value]); 
    } 
} 
2

при использовании раствора RegEx Marc Gravell, в первую очередь проверьте, если маркер доступен используя т.е. ContainsKey, чтобы это предотвратить ошибки KeyNotFoundException:

string output = re.Replace(zpl, match => { return args.ContainsKey(match.Groups[1].Value) ? arg[match.Groups[1].Value] : match.Value; }); 

при использовании следующей слегка модифицированный пример кода (первый параметр имеет другое имя):

var args = new Dictionary<string, string>(
     StringComparer.OrdinalIgnoreCase) 
     { 
      {"nameWRONG", "Mr Smith"}, 
      {"date", "05 Aug 2009"}, 
      {"AMOUNT", "GBP200"} 
     }; 

это производит следующее:

"Дорогой $ имя $, по состоянию на 05 августа 2009 Ваш баланс GBP200"

0

Здесь вы:

public static class StringExm 
{ 
    public static String ReplaceAll(this String str, KeyValuePair<String, String>[] map) 
    { 
     if (String.IsNullOrEmpty(str)) 
      return str; 

     StringBuilder result = new StringBuilder(str.Length); 
     StringBuilder word = new StringBuilder(str.Length); 
     Int32[] indices = new Int32[map.Length]; 

     for (Int32 characterIndex = 0; characterIndex < str.Length; characterIndex++) 
     { 
      Char c = str[characterIndex]; 
      word.Append(c); 

      for (var i = 0; i < map.Length; i++) 
      { 
       String old = map[i].Key; 
       if (word.Length - 1 != indices[i]) 
        continue; 

       if (old.Length == word.Length && old[word.Length - 1] == c) 
       { 
        indices[i] = -old.Length; 
        continue; 
       } 

       if (old.Length > word.Length && old[word.Length - 1] == c) 
       { 
        indices[i]++; 
        continue; 
       } 

       indices[i] = 0; 
      } 

      Int32 length = 0, index = -1; 
      Boolean exists = false; 
      for (int i = 0; i < indices.Length; i++) 
      { 
       if (indices[i] > 0) 
       { 
        exists = true; 
        break; 
       } 

       if (-indices[i] > length) 
       { 
        length = -indices[i]; 
        index = i; 
       } 
      } 

      if (exists) 
       continue; 

      if (index >= 0) 
      { 
       String value = map[index].Value; 
       word.Remove(0, length); 
       result.Append(value); 

       if (word.Length > 0) 
       { 
        characterIndex -= word.Length; 
        word.Length = 0; 
       } 
      } 

      result.Append(word); 
      word.Length = 0; 
      for (int i = 0; i < indices.Length; i++) 
       indices[i] = 0; 
     } 

     if (word.Length > 0) 
      result.Append(word); 

     return result.ToString(); 
    } 
} 
+1

Вы можете добавить какое-либо объяснение или комментарий к своему ответу, чтобы читатели не должны внимательно проверять код, чтобы понять, что вы предлагаете. Тем более, что это довольно длинный фрагмент, намного дольше, чем другие предлагаемые решения. –

+0

Он делает то, что хотел автор. В отличие от других, он не использует регулярные выражения и проходит через линию только один раз, что важно, когда вам нужно произвести несколько десятков замен. – Albeoris

+0

Похоже, что он игнорирует границы слов и, кажется, очень подвержен ошибкам. С другой стороны, никаких объяснений нет, поэтому я могу ошибаться. –

Смежные вопросы