Is there a better way to count string format placeholders in a string in C#?
Merging Damovisa's and Joe's answers. I've updated answer afer Aydsman's nad activa's comments.
int count = Regex.Matches(templateString, @"(?<!\{)\{([0-9]+).*?\}(?!})") //select all placeholders - placeholder ID as separate group
.Cast<Match>() // cast MatchCollection to IEnumerable<Match>, so we can use Linq
.Max(m => int.Parse(m.Groups[1].Value)) + 1; // select maximum value of first group (it's a placegolder ID) converted to int
This approach will work for templates like:
"{0} aa {2} bb {1}" => count = 3
"{4} aa {0} bb {0}, {0}" => count = 5
"{0} {3} , {{7}}" => count = 4
Counting the placeholders doesn't help - consider the following cases:
"{0} ... {1} ... {0}" - needs 2 values
"{1} {3}" - needs 4 values of which two are ignored
The second example isn't farfetched.
For example, you may have something like this in US English:
String.Format("{0} {1} {2} has a {3}", firstName, middleName, lastName, animal);
In some cultures, the middle name may not be used and you may have:
String.Format("{0} {2} ... {3}", firstName, middleName, lastName, animal);
If you want to do this, you need to look for the format specifiers {index[,length][:formatString]} with the maximum index, ignoring repeated braces (e.g. {{n}}). Repeated braces are used to insert braces as literals in the output string. I'll leave the coding as an exercise :) - but I don't think it can or should be done with Regex in the most general case (i.e. with length and/or formatString).
And even if you aren't using length or formatString today, a future developer may think it's an innocuous change to add one - it would be a shame for this to break your code.
I would try to mimic the code in StringBuilder.AppendFormat (which is called by String.Format) even though it's a bit ugly - use Lutz Reflector to get this code. Basically iterate through the string looking for format specifiers, and get the value of the index for each specifier.