C#字符串替换为字典

时间:2009-08-05 07:58:42

标签: c# string dictionary replace

我有一个字符串,我需要做一些替换。我有Dictionary<string, 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;
}

有更好的方法吗?

8 个答案:

答案 0 :(得分:43)

如果数据被标记化(即“亲爱的$ name $,从$ date $开始,你的余额是$ amount $”),那么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实际上是一个问题吗?

答案 1 :(得分:24)

使用Linq执行此操作:

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

dict 是您的搜索替换对定义的Dictionary对象。

str 是您需要替换的字符串。

答案 2 :(得分:9)

对我来说似乎是合理的,除了一件事:它是对订单敏感的。例如,输入一个“$ x $ y”的输入字符串和一个替换字典:

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

替换的结果是 “foo foo”或“$ y foo”,具体取决于首先执行的替换。

您可以使用List<KeyValuePair<string, string>>来控制排序。另一种方法是遍历字符串,确保在进一步的替换操作中不使用替换。但这可能要困难得多。

答案 3 :(得分:4)

这是@ Marc的一个很好的重新考虑的版本的答案,使功能可用作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]);
    }
}

答案 4 :(得分:2)

使用Marc Gravell的RegEx解决方案时,首先使用ie 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"}
        };

这会产生以下结果:

“亲爱的$ name $,截至2009年8月5日,您的余额为200英镑”

答案 5 :(得分: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();
    }
}

答案 6 :(得分:0)

完成此任务的正确工具是Mustache,这是一种简单的标准无逻辑模板语言。

有很多实现。在此示例中,我将使用stubble

var stubble = new StubbleBuilder().Build();
var dataHash = new Dictionary<string, Object>()
{
    {"Foo","My Foo Example"},
    {"Bar",5}
};

var output = stubble.Render(
   "Hey, watch me replace this: {{Foo}} ... with example text.  Also {{bar}} is 5"
   , dataHash
);

答案 7 :(得分:0)

为什么不仅仅检查这种密钥是否存在?

  • 如果存在,则删除该对,否则,跳过此步骤;

  • 添加相同的键,但现在具有新的期望值。

      // say, you have the following collection
      var fields = new Dictionary<string, string>();
      fields.Add("key1", "value1");
      fields.Add("key2", "value2");
      fields.Add("key3", "value3");
    
      // now, you want to add a pair "key2"/"value4"
      // or replace current value of "key2" with "value4"
      if (fields.ContainsKey("key2"))
      {
          fields.Remove("key2");
      }
      fields.Add("key2", "value4");