我有一个(大)模板,想要替换多个值。替换需要不区分大小写。还必须能够拥有模板中不存在的密钥。
例如:
[TestMethod]
public void ReplaceMultipleWithIgnoreCaseText()
{
const string template = "My name is @Name@ and I like to read about @SUBJECT@ on @website@, tag @subject@";
const string expected = "My name is Alex and I like to read about C# on stackoverflow.com, tag C#";
var replaceParameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("@name@","Alex"),
new KeyValuePair<string, string>("@subject@","C#"),
new KeyValuePair<string, string>("@website@","stackoverflow.com"),
// Note: The next key does not exist in template
new KeyValuePair<string, string>("@country@","The Netherlands"),
};
var actual = ReplaceMultiple(template, replaceParameters);
Assert.AreEqual(expected, actual);
}
public string ReplaceMultiple(
string template,
IEnumerable<KeyValuePair<string, string>> replaceParameters)
{
throw new NotImplementedException(
"Implementation needed for many parameters and long text.");
}
请注意,如果我有30个参数和一个大模板的列表,我不希望内存中有30个大字符串。使用StringBuilder似乎是一种选择,但也欢迎其他解决方案。
解决方案我尝试了但没有工作
此处找到的解决方案(C# String replace with dictionary)会在密钥不在收集中时引发异常,但我们的用户会犯错误,在这种情况下,我只想将wromg密钥保留在文本中。例如:
static readonly Regex re = new Regex(@"\$(\w+)\$", RegexOptions.Compiled);
static void Main2()
{
// "Name" is accidentally typed by a user as "nam".
string input = @"Dear $nam$, as of $date$ your balance is $amount$";
var args = new Dictionary<string, string>(
StringComparer.OrdinalIgnoreCase) {
{"name", "Mr Smith"},
{"date", "05 Aug 2009"},
{"amount", "GBP200"}};
// Works, but not case insensitive and
// uses a lot of memory when using a large template
// ReplaceWithDictionary many args
string output1 = input;
foreach (var arg in args)
{
output1 = output1.Replace("$" + arg.Key +"$", arg.Value);
}
// Throws a KeyNotFoundException + Only works when data is tokenized
string output2 = re.Replace(input, match => args[match.Groups[1].Value]);
}
答案 0 :(得分:4)
使用StringBuilder似乎是一种选择,但也欢迎使用其他解决方案。
由于你想要不区分大小写,我建议(非StringBuilder):
public static string ReplaceMultiple(
string template,
IEnumerable<KeyValuePair<string, string>> replaceParameters)
{
var result = template;
foreach(var replace in replaceParameters)
{
var templateSplit = Regex.Split(result,
replace.Key,
RegexOptions.IgnoreCase);
result = string.Join(replace.Value, templateSplit);
}
return result;
}
答案 1 :(得分:3)
static readonly Regex re = new Regex(@"\b(\w+)\b", RegexOptions.Compiled);
static void Main(string[] args)
{
string input = @"Dear Name, as of dAte your balance is amounT!";
var replacements = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{"name", "Mr Smith"},
{"date", "05 Aug 2009"},
{"amount", "GBP200"}
};
string output = re.Replace(input, match => replacements.ContainsKey(match.Groups[1].Value) ? replacements[match.Groups[1].Value] : match.Groups[1].Value);
}
这是5000次迭代测试基准测试,没有查看内存或其他任何内容。
替换功能是您已检查为已接受答案的功能。
答案 2 :(得分:0)
我想我可能会尝试一些东西。我在电子邮件模板中使用了类似的东西
public string replace()
{
string appPath = Request.PhysicalApplicationPath;
StreamReader sr = new StreamReader(appPath + "EmailTemplates/NewMember.txt");
string template = sr.ReadToEnd();
template = template.Replace("<%Client_Name%>",
first_name.Text + " " + middle_initial.Text + " " + last_name.Text);
//Add Customer data
template = template.Replace("<%Client_First_Name%>", first_name.Text);
template = template.Replace("<%Client_MI%>", middle_initial.Text);
template = template.Replace("<%Client_Last_Name%>", last_name.Text);
template = template.Replace("<%Client_DOB%>", dob.Text);
return template;
}
在模板内部,您可以使用&lt; %%&gt;等标记。作为你想要的价值观的占位符
希望这有帮助!
答案 3 :(得分:0)
Marc Gravell的答案:C# String replace with dictionary可以稍微更改一下,以便在找不到匹配时不会抛出异常。在这种情况下,它根本不会取代匹配。
如果要替换的字符串是标记化的,这就是解决方案:
static readonly Regex RegExInstance = new Regex(@"\$(\w+)\$", RegexOptions.Compiled);
public string ReplaceWithRegEx(string template, Dictionary<string, string> parameters)
{
return RegExInstance.Replace(template, match => GetNewValue(parameters, match));
}
private string GetNewValue(Dictionary<string, string> parameters, Match match)
{
var oldValue = match.Groups[1].Value;
string newValue;
var found = parameters.TryGetValue(oldValue, out newValue);
if (found)
{
return newValue;
}
var originalValue = match.Groups[0].Value;
return originalValue;
}
我已经使用100.000字节字符串,7个密钥和数百个替换项测试了该解决方案。它使用的内存比字符串的长度多7倍。它只花了0.002秒。