如何为字符串格式提供自定义字符串占位符

我有一个字符串

string str ="Enter {0} patient name"; 

我正在使用string.format来格式化它。

 String.Format(str, "Hello"); 

现在,如果我想要从某些配置中检索患者,那么我需要将str更改为"Enter {0} {1} name" 。 因此它将用第二个值替换{1}。 问题是我想要{1}而不是{1}其他格式的东西,比如{pat} 。 但是当我尝试使用时,它会抛出一个错误。 我想要一种不同格式的原因是我需要改变很多文件(可能包含{0},{1}等)。 所以我需要一个可以在运行时替换的自定义占位符。

你可能想看看James Newton-King的 FormatWith 2.0 。 它允许您使用属性名称作为格式化标记,例如:

 var user = new User() { Name = "Olle Wobbla", Age = 25 }; Console.WriteLine("Your name is {Name} and your age is {Age}".FormatWith(user)); 

您也可以将它与匿名类型一起使用。

更新: Scott Hanselman也有类似的解决方案 ,但它是作为Object而不是String一组扩展方法实现的。

更新2012 :您可以在NuGet.org上获得Calrius Consulting的NETFx String.FormatWith扩展方法 NuGet包

更新2014 :还有StringFormat.NET和littlebit的StringFormat

使用MatchEvaluator Regex似乎是一个不错的选择:

 static readonly Regex re = new Regex(@"\{([^\}]+)\}", RegexOptions.Compiled); static void Main() { string input = "this {foo} is now {bar}."; StringDictionary fields = new StringDictionary(); fields.Add("foo", "code"); fields.Add("bar", "working"); string output = re.Replace(input, delegate (Match match) { return fields[match.Groups[1].Value]; }); Console.WriteLine(output); // "this code is now working." } 

我看到上面的所有答案,然而,无法正确的问题:)

以下代码是否有任何特殊原因不符合您的要求?

 string myFirstStr = GetMyFirstStrFromSomewhere(); string mySecondStr = GetMySecondStrFromSomewhere(); string result = "Enter " + myFirstStr + " " + mySecondStr + " name"; 
 object[] myInts = new int[] {8,9}; 

但是你可以逃脱:

 object[] myInts = new string[] { "8", "9" }; string bar = string.Format("{0} {1}", myInts); 

这是我在这里找到的另一个版本: http : //www.reddit.com/r/programming/comments/bodml/beef_up_params_in_c_5_to_solve_lambda_abuse/c0nrsf1

对此的任何解决方案都将涉及reflection,这不太理想,但这是他的代码解决了一些其他主要性能问题。 (没有错误检查。如果你愿意,可以添加它。):

1)使用直接运行时reflection,没有DataBinder开销

2)不使用正则表达式,使用单遍解析和状态。

3)不将字符串转换为中间字符串,然后再将其转换为最终格式。

4)使用单个StringBuilder分配和连接,而不是在整个地方新建字符串并将它们连接成新的字符串。

5)删除为n个替换操作调用委托的堆栈开销。

6)一般来说,单次传递将以相对线性的方式进行缩放(对于每个prop查找和嵌套的prop查找仍然需要一些成本,但就是这样。)

 public static string FormatWith(this string format, object source) { StringBuilder sbResult = new StringBuilder(format.Length); StringBuilder sbCurrentTerm = new StringBuilder(); char[] formatChars = format.ToCharArray(); bool inTerm = false; object currentPropValue = source; for (int i = 0; i < format.Length; i++) { if (formatChars[i] == '{') inTerm = true; else if (formatChars[i] == '}') { PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString()); sbResult.Append((string)(pi.PropertyType.GetMethod("ToString", new Type[]{}).Invoke(pi.GetValue(currentPropValue, null), null))); sbCurrentTerm.Clear(); inTerm = false; currentPropValue = source; } else if (inTerm) { if (formatChars[i] == '.') { PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString()); currentPropValue = pi.GetValue(source, null); sbCurrentTerm.Clear(); } else sbCurrentTerm.Append(formatChars[i]); } else sbResult.Append(formatChars[i]); } return sbResult.ToString(); } 

您还可以使用Marc Gravell中的示例并扩展String类对象:

 public static class StringExtension { static readonly Regex re = new Regex(@"\{([^\}]+)\}", RegexOptions.Compiled); public static string FormatPlaceholder(this string str, Dictionary fields) { if (fields == null) return str; return re.Replace(str, delegate(Match match) { return fields[match.Groups[1].Value]; }); } } 

用法示例:

 String str = "I bought a {color} car"; Dictionary fields = new Dictionary(); fields.Add("color", "blue"); str.FormatPlaceholder(fields)); 

你可能最好使用Replace替换自定义字段,使用Format替换其余字段,例如:

 string str = "Enter {0} {pat} name"; String.Format(str.Replace("{pat}", "Patient"), "Hello"); 

我想要的东西更像Python的字符串格式,所以我写了这个: https : //gist.github.com/samwyse/b225b32ae1aea6fb27ad9c966b9ca90b

像这样用它:

 Dim template = New FormatFromDictionary("{cat} vs {dog}") Dim d = New Dictionary(Of String, Object) From { {"cat", "Felix"}, {"dog", "Rex"}} Console.WriteLine(template.Replace(d)) ' Felix vs Rex