您可以使用正则表达式,例如 {(.*?)},然后只计算匹配项。如果您需要处理像 {0} {0} 这样的情况(我猜应该返回 1),那么这会变得更加困难,但是您始终可以将所有匹配项放入列表中,然后对其执行 Linq select unique 操作。我在想类似下面的代码:
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);
EDIT:
我想解决评论中提出的一些问题。下面发布的更新代码处理存在转义括号序列(即 {{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);