CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Karl Seguin

developer @ Fuel Industries ottawa, ontario

code better - use string.format

Poorly handled exceptions might speak volumes about someone's coding abilities, but it's string concatenation that's a sure bet to kill a programs readability (thus maintainability). Everyone knows that they should use StringBuilder's for better performance when concatenating a lot, but to improve maintainability, string.format is king!

On the topic of performance though, you'll be glad to know that there's also an AppendFormat method to the stringbuilder class - so readability and performance aren't exclusive concepts!

Surely, I can't be the only one that has a hard time writing and maintaining code like:
document.SelectSingleNode("/graph/data[name='" + name + "']");

When I do write code like the above, I almost always forget my closing quote or square bracket! And as things get more complicated, it becomes a flat out nightmare.

The solution is to make heavy use of string.Format. You'll never EVER see me use + (or & in VB.NET) to concatenate something to a string, and there's no reason you should either. To write the above code better, try:
document.SelectSingleNode(string.Format("/graph/data[name='{0}']", name));

Personally, even though it's a simple example, I find it a lot better - and as things get more complicated you'll be laughing as you code. But wait, there's more!  string.Format uses string formatting - so you have a lot of control over how objects are turned into strings. So you coul do
string.Format("Your score is {0:p}", student.FinalExam.Score); 
which would format the float score into a percentage.

Understanding .NET String formatting is important because (a) it'll make it so you never ask a question about how to get a date in a certain format, (b) how to get a number in a certain format and (c) it's used all over in .NET.  For example, that DataBinder.Eval() method actually accepts a 3rd parameter which is the string formatter to use.

Now, like I said earlier, you can also use AppendFormat of the StringBuilder class

StringBuilder sb = new StringBuilder();
sb.Append("<books>");
foreach(Book book in author.Books)
{
   sb.AppendFormat("<book isbn=\"{0}\">{1}</book>", book.Isbn, book.Name);
}
sb.Append("</books>");

A word of caution. String.format IS NOT a substitute for using command parameters. But dang, it is sweet for almost everything else!

Published Apr 10 2006, 03:01 PM by karl
Filed under:

Comments

Rajiv Menon said:

Hey Karl,
Here's a cool article on string formatting from Kathy.
link: http://blogs.msdn.com/kathykam/archive/2006/03/29/564426.aspx
# April 11, 2006 12:19 AM

Christopher Steen said:

&quot;Atlas&quot; April CTP Release [Via: Rich Ersek ]
[T-SQL] Call a stored procedure once for each row in a...
# April 12, 2006 10:24 PM

Sharbel said:

Good article

String.Format() is fantastic for 2-4 concats.  Also, i recall performace tests showing StringBuilders were a waste for under 5 concats, and using String.Format() is perfectly acceptable.
# April 21, 2006 5:02 PM

-:[web caboodle]:- said:

# April 21, 2006 10:33 PM

programer said:

good article,study
# April 23, 2006 12:55 AM

GR KHAN said:

Please give code that how we convert numbers into arabic language.
Thanks,
# April 23, 2006 9:40 AM

John Papa said:

Good post, Karl. I generally use string.Format(...) for 3 (+/-) or less concats. Otherwise I use Stringbuilder. The plus or minus is there because I use the good ol' eyeball technique to make sure it passes the readability test :)
# April 23, 2006 11:17 AM

karl said:

GR KHAN:
Using the out-of-the-box Globalization features of .NET,it's only possible to localize currency symbol, decimal separators, and other numeric symbols. I don't believe there's a straightfoward way to convert a Int32 into a localized version of the # unfortunetly (though I could be wrong).

This is the best I could find which might help you:
http://www.codeproject.com/csharp/num_to_arabic.asp
# April 23, 2006 11:38 AM

pecha said:

Nice article! But few days ago I found that string.Format works very slow. Example with + .. + (see below) executes in 1 sec, with string.Format this is about 6 sec!! in VS 2005.

string userID = "ccf5acf6-2d28-4077-83d4-9fa6685057d4";
Console.WriteLine(DateTime.Now.ToLongTimeString());
for (int i = 0; i < 5000000; i++)
{
   string a = "SELECT * FROM TTT WHERE UserID = '" + userID + "' ORDER BY BBB DESC LIMIT 1";
}
Console.WriteLine(DateTime.Now.ToLongTimeString());
Console.WriteLine("---------------------------------");
Console.WriteLine(DateTime.Now.ToLongTimeString());
for (int i = 0; i < 5000000; i++)
{
   string a = String.Format("SELECT * FROM TTT WHERE UserID = '{0}' ORDER BY BBB DESC LIMIT 1", userID);
}
Console.WriteLine(DateTime.Now.ToLongTimeString());

Console.Read();
# April 25, 2006 6:05 PM

karl said:

I did say you should never use string.Format in lieu of command parameters. Anyways, that point aside, I guess you should always take into account performance, but almost anyone should be willing to pay the price for a 6 second delay over 5 million iteration for varstly improved readability.

Remember, you can always use the AppendFormat method of the StringBuilder for a lot of concatenation..works just like string.Format..
# April 25, 2006 7:25 PM

pecha said:

I absolutely agree with you, string.Format this is a very nice feature. I just showed small example, maybe for someone it will be interesting.
# April 26, 2006 5:09 AM

Ayende Rahien said:

Pecha,
Just to note, the first version doesn't do anything, the compiler concantated in in compile time.
# April 29, 2006 11:35 AM

Scott Van Vliet said:

I use String.Format everywhere! And infact, it uses StringBuilder under-the-hood:

public static string Format(IFormatProvider provider, string format, params object[] args)
{
     if ((format == null) || (args == null))
     {
           throw new ArgumentNullException((format == null) ? "format" : "args");
     }
     StringBuilder builder1 = new StringBuilder(format.Length + (args.Length * 8));
     builder1.AppendFormat(provider, format, args);
     return builder1.ToString();
}

Cheers.
# May 8, 2006 6:16 PM

Karl Seguin [MVP] said:

As I've indicated in the past, I'm a pretty big fan of string.Format and anything else that accepts a...
# May 15, 2006 10:27 AM

Karl Seguin [MVP] said:

I hate taking over someone's bad code. The projects always go on forever and you are forced to follow...
# May 18, 2006 5:20 PM

Brian said:

Is there a character limit on the target string which is being formatted?
# June 14, 2006 6:23 PM

karl said:

Brian:
I'm under the strong impressions that string's in .NET have no real upper limit, other than what the OS (32 bits) imposes and whatever overhead .NET has (like the fact that all chars are unicode, so cut that in 1/2).
# June 14, 2006 6:46 PM

Brian said:

Here's my trouble:

I have a little .NET Windows Forms utility that I'm working on that helps generate my C# code-behind files for an ASP.NET application.

I have three different strings I'm trying to format. The first two strings work just fine, then the 3rd string gives me this System.FormatException error:
        "Input string was not in a correct format."

//String #1: (works ok)
   string input = "\t\tprotected System.Web.UI.WebControls.CheckBoxList Q{0};";

//String #2: (works ok)
   string input = "this.Q{0}.SelectedIndexChanged += new System.EventHandler(this.Q{0}_SelectedIndexChanged);";

//String #3: (error raised)
 string input = "\tprivate void Q{0}_SelectedIndexChanged(object sender, System.EventArgs e) {";

Here's my syntax for formatting the above INPUT strings (which in my actual code are pulled out of a database into objects):

String.Format(input,param);

//the param in these cases are an Int32.ToString() which I am wanting to insert.
# June 15, 2006 7:58 AM

Brian said:

I originally thought there was a character limit issue that I was encountering (because my 3rd string was actually a big block of .NET code that I was trying to format.

But even the shortened format from my above example will fail. So I don't know what I'm doing wrong.

Thanks for any and all of your help!

Brian
# June 15, 2006 8:01 AM

karl said:

Brian:
The problem is that you have a { at the end of your 3rd example. { is a special character in string.Format, so it's causing it to have a hicup.

You should be able to escape the { with a double {{, ala:
string input = "\tprivate void Q{0}_SelectedIndexChanged(object sender, System.EventArgs e) {{";

but that doesn't seem to work, and I honestly can't put my finger on why this morning...

This works:
string input = "\tprivate void Q{0}_SelectedIndexChanged(object sender, System.EventArgs e) {1}";
string.Format(input, 123, "{{");

which is a little weird. I'll try to look more into it.


# June 15, 2006 8:23 AM

Paul Chu said:

I was getting an error too with the embedded braces.

I added additional  parameters to insert the  braces with String.Format

{0}  --> "{"

{1}  --> "}"

function x()

{0}

alert('test');

{1}

Regards, Paul

paulchu8@gmail.com

# September 25, 2006 1:08 AM

Travis001 said:

I find it somewhat funny that given the extremely slow performance of the String.Format function anyone would want to use it.

To say that as developer it is more important that we have pretty code then to have a function that takes between 4-6 times longer is pathetic. I believe that you can have nice looking code that is also concerned about performance.

Just remember that if you are writing good software you actually have customers using it and those milliseconds add up quickly.

# October 4, 2006 1:27 PM

Karl Seguin [MVP] said:

In response to my post evangilizing string.format , Travis commented that my advice was wrong, and that

# October 4, 2006 7:41 PM

Haacked said:

Right.. because I heard that string.format takes around two hours to properly format a string.

# October 4, 2006 9:47 PM

DaRage said:

Travis, milliseconds don't add up quickly and to believe so is mere pathetic paranoia. let the cpu do its work and let the developers to do theirs.

# October 5, 2006 8:28 AM

Tony B said:

A quick Google (trying to see what the real impact on perf is)

My favorite perf guru: http://blogs.msdn.com/ricom/archive/2004/03/12/88715.aspx

# October 5, 2006 9:06 AM

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# October 6, 2006 8:47 AM

Imran Aziz said:

nice one, I get into formating issues so many times specially while creating html in code, its nice to be reminded about using something that is already supported well by the language.

# October 10, 2006 11:20 AM

lb said:

top article Karl!

i'm a fan of string.Format but when simply concatenating a small number of strings together, i prefer string.Concat

it's faster under the hood than string.format because it doesn't need to parse the string for arguments.

so there's four important tools here, each with their own niche:

string.format

string.concat

stringbuilder.append

stringbuilder.appendformat

that way you get performance/flexibility in just the right amount.

if you use string.format where string.Concat is more apt you do take an unwanted performance hit.

Always enjoy your stuff, Karl.

lb

# October 10, 2006 7:51 PM

Neil said:

I'm having trouble converting a long (125kb...not really that long is it?) byte array (that I read from a binary file using ReadAllBytes) to a string in under 10 minutes... I've tried several methods (including BitConverter), but however I do it there's a bottleneck when building the string:/

As you say,  StringBuilder.Append works much faster than concantenating, but I still need to convert the stringbuilder back to a string at some point in order to use Contains and SubString  later on to process the file - at which point the StringBuilder.ToString takes ages!

Does anyone have any ideas?

Cheers

# October 17, 2006 9:56 PM

karl said:

Would you be able to post a sample project somewhere in a zip?

Have you tried a profiler,such as RedGate's Ants or JetBrain's dotTrace? I think they both have fully functional trials...

# October 18, 2006 6:37 AM

s said:

s

# December 20, 2006 1:51 AM

Betta Glurpse said:

I disagree. I admit that in your short one-argument example using quotes, the String.Format version is slightly more readable. But most often, I find that String.Format is less maintainable compared to concatenation with +. The main reason is that with ordinary concatenation, the arguments are kept where they are used, namely inside the string. This is good.

Consider this:

db.executeStatement(String.Format("UPDATE {0} SET owner_id={1} where owner_id is null and {2}", name, id, whereClause));

This is bad for two reasons:

1) MENTAL OVERHEAD CORRELATING PARAMETERS TO ARGUMENTS: When checking this statement, I have to remember that argument 0 is the table name, 1 is the owner id and so on until I reach the argument list and can see that there is a match. In particular, this makes it harder to decipher what poorly named variables such as "name" and "id" in the example above are being used for.

2) RENUMBERING OR DISORDER: If for some reason I need to set an additional column value in the example above, I have to either renumber the folowing arguments, or accept further mental overhead because the arguments are no longer used in the order they appear:

db.executeStatement(String.Format("UPDATE {0} SET owner_id={1}, ttime={3} where owner_id is null and {2}", name, id, whereClause, transactiontime));

# January 15, 2007 7:02 AM

karl said:

Betta:

I agree that in some cases it might be worse off. But I do think that when you get into a lot of escaping, using + is a nightmare. Sticking with your not-so-good SQL example (since parameterized queries are better than both approaches)...

"insert into users (username, password, type) values ('" + name + "', '" + password + "', " + type +")"

isn't fun to write.  I forgot a couple +'s writing this out the first time and have always found it hard to read "'

again, the SQL query example isn't the best though...

# January 15, 2007 8:26 AM

Betta Glurpse said:

Great to hear. There is nothing worse than people who categorically dismiss arguments that don't fit with their own preference - thankfully, you don't seem to be one of them. And yes, more readable quoting is one of the pros of using String.Format.

On another note, I absolutely agree my example isn't good database programming (with vulnerability to SQL injection being just one reason), but I think it is a decent representative "format" string. Many error messages, which probably accounts for a large portion of formatted strings, are "parameterized" in a similar fashion.

# January 16, 2007 4:25 AM

psmithphil said:

I just want to thank the author for an excellent article.  This has opened up a new world for strings for me.

# April 28, 2007 9:49 PM

Sameer Alibhai said:

I totally agree with Karl, that String.Format is much more readable.  Here is my post on why: www.sharpdeveloper.net/.../use-string.format-instead-of-chopping-strings.aspx

# May 31, 2007 11:16 AM

Jonas said:

I agree on all you are saying about using

string.Format.

But I find it "ironic" that you end the post with string building XML.

What will happen when someone retreives the book; book.Name == "101 ? & Answers"

Thanks for a good article

/Jonas

# June 29, 2007 12:23 AM

paul said:

hi kerl,

what is the use of string concat

# August 22, 2007 5:46 AM

karl said:

Paul:

string.Concat is useful because of it's speed, but it isn't much more readable than using +.

I use string.Concat a lot when dealing with 1 (maybe 2) variables:

string cacheKey = string.Concat("userId:", userId);

# August 22, 2007 7:52 PM

Using String.Format for string formatting « Manoj Garg’s Tech Blog said:

Pingback from  Using String.Format for string formatting &laquo; Manoj Garg&#8217;s Tech Blog

# April 29, 2008 4:53 AM

String.Format(); « namespace Programatik said:

Pingback from  String.Format(); &laquo; namespace Programatik

# May 14, 2008 2:13 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!