Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
301 views
in Technique[技术] by (71.8m points)

.net - Is there a better way to count string format placeholders in a string in C#?

I have a template string and an array of parameters that come from different sources but need to be matched up to create a new "filled-in" string:

string templateString = GetTemplate();   // e.g. "Mr {0} has a {1}"
string[] dataItems = GetDataItems();     // e.g. ["Jones", "ceiling cat"}

string resultingString = String.Format(templateString, dataItems);
// e.g. "Mr Jones has a ceiling cat"

With this code, I'm assuming that the number of string format placeholders in the template will equal the number of data items. It's generally a fair assumption in my case, but I want to be able to produce a resultingString without failing even if the assumption is wrong. I don't mind if there are empty spaces for missing data.

If there are too many items in dataItems, the String.Format method handles it fine. If there aren't enough, I get an Exception.

To overcome this, I'm counting the number of placeholders and adding new items to the dataItems array if there aren't enough.

To count the placeholders, the code I'm working with at the moment is:

private static int CountOccurrences(string haystack)
{
    // Loop through all instances of the string "}".
    int count = 0;
    int i = 0;
    while ((i = text.IndexOf("}", i)) != -1)
    {
        i++;
        count++;
    }
    return count;
}

Obviously this makes the assumption that there aren't any closing curly braces that aren't being used for format placeholders. It also just feels wrong. :)

Is there a better way to count the string format placeholders in a string?


A number of people have correctly pointed out that the answer I marked as correct won't work in many circumstances. The main reasons are:

  • Regexes that count the number of placeholders doesn't account for literal braces ( {{0}} )
  • Counting placeholders doesn't account for repeated or skipped placeholders (e.g. "{0} has a {1} which also has a {1}")
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...