我有一个字符串,我需要做一些替换。我有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;
}
有更好的方法吗?
答案 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");