Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String.Format count the number of expected args

Tags:

string

c#

.net

Is it possible to count the number of expected args/params in a string for String.Format()?

For example: "Hello {0}. Bye {1}" should return a count of 2.

I need to display an error before the string.Format() throws an exception.

Thanks for your help.

like image 227
Divi Avatar asked Feb 14 '11 05:02

Divi


People also ask

How many arguments string function takes?

Except for functions with variable-length argument lists, the number of arguments in a function call must be the same as the number of parameters in the function definition. This number can be zero. The maximum number of arguments (and corresponding parameters) is 253 for a single function.

Why use string format?

Use String.Format if you need to insert the value of an object, variable, or expression into another string.

What does format do in rust?

Creates a String using interpolation of runtime expressions.


1 Answers

You could use a regex, something like {(.*?)} and then just count the matches. If you need to handle cases like {0} {0} (which I guess should return 1) then that makes it a little more difficult, but you could always put all of the matches in a list an do a Linq select distinct on it. I'm thinking something like the code below:

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:

I wanted to address some of the concerns raised in the comments. The updated code posted below handles the cases where there are escaped bracket sequences (i.e., {{5}}), where no parameters are specified, and also returns the value of the highest parameter + 1. The code assumes that the input strings will be well formed, but that trade off may be acceptable in some cases. For example, if you know that the input strings are defined in an application and not generated by user input, then handling all of the edge cases may not be necessary. It might also be possible to test all of the error messages to be generated using a unit test. The thing I like about this solution is that it will most likely handle the vast majority of the strings that are thrown at it, and it is a simpler solution than the one identified here (which suggests a reimplementation of string.AppendFormat). I would account for the fact that this code might not handle all edge cases by using a try-catch and just returning "Invalid error message template" or something to that effect.

One possible improvement for the code below would be to update the regex to not return the leading "{" characters. That would eliminate the need for the Replace("{", string.Empty). Again, this code might not be ideal in all cases, but I feel it adequately addresses the question as asked.

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);
like image 137
rsbarro Avatar answered Oct 03 '22 08:10

rsbarro