您可以使用正则表达式,例如 {(.*?)},然后只计算匹配项。如果您需要处理像 {0} {0} (我猜应该返回 1)这样的情况,那么这会使它变得更加困难,但是您总是可以将所有匹配项放在一个列表中并在其上执行 Linq select distinct .我在想类似下面的代码:
var input = "{0} and {1} and {0} and {2:MM-dd-yyyy}";
var pattern = @"{(.*?)}";
var matches = Regex.Matches(input, pattern);
var totalMatchCount = matches.Count;
var uniqueMatchCount = matches.OfType<Match>().Select(m => m.Value).Distinct().Count();
Console.WriteLine("Total matches: {0}", totalMatchCount);
Console.WriteLine("Unique matches: {0}", uniqueMatchCount);
编辑:
我想解决 cmets 中提出的一些问题。下面发布的更新代码处理存在转义括号序列(即 {{5}})的情况,其中未指定参数,并且还返回最高参数的值 + 1。代码假定输入字符串将格式良好,但在某些情况下这种权衡可能是可以接受的。例如,如果您知道输入字符串是在应用程序中定义的,而不是由用户输入生成的,则可能不需要处理所有边缘情况。也可以使用单元测试来测试要生成的所有错误消息。我喜欢这个解决方案的一点是,它很可能会处理向它抛出的绝大多数字符串,而且它比here 标识的解决方案更简单(这表明重新实现 string.AppendFormat)。我会考虑这样一个事实,即此代码可能无法通过使用 try-catch 并仅返回“无效的错误消息模板”或类似的东西来处理所有边缘情况。
以下代码的一个可能改进是更新正则表达式以不返回前导“{”字符。这将消除对 Replace("{", string.Empty) 的需要。同样,此代码可能并非在所有情况下都是理想的,但我认为它充分解决了所提出的问题。
const string input = "{0} and {1} and {0} and {4} {{5}} and {{{6:MM-dd-yyyy}}} and {{{{7:#,##0}}}} and {{{{{8}}}}}";
//const string input = "no parameters";
const string pattern = @"(?<!\{)(?>\{\{)*\{\d(.*?)";
var matches = Regex.Matches(input, pattern);
var totalMatchCount = matches.Count;
var uniqueMatchCount = matches.OfType<Match>().Select(m => m.Value).Distinct().Count();
var parameterMatchCount = (uniqueMatchCount == 0) ? 0 : matches.OfType<Match>().Select(m => m.Value).Distinct().Select(m => int.Parse(m.Replace("{", string.Empty))).Max() + 1;
Console.WriteLine("Total matches: {0}", totalMatchCount);
Console.WriteLine("Unique matches: {0}", uniqueMatchCount);
Console.WriteLine("Parameter matches: {0}", parameterMatchCount);