Thursday, February 12, 2009

String concatenation made easy

How many times have you written code similar to this?

   1: var builder = new StringBuilder();
   2:  
   3: foreach (string foo in bar)
   4: {
   5:     builder.Append(foo);    
   6: }
   7:  
   8: return builder.ToString();

I have hopefully done it for the last time since I created a couple of extension methods for IEnumerable<string>, well actually, one method with a couple of overloads.

The first one is really simple and just concatenates all the strings in the specified collection to a single string, something like:

   1: var sequence = new string[] { "foo", "bar" };
   2: string result = sequence.Concatenate();

In this case the result variable will contain the string “foobar”. One of the overloads will let you specify a separator:

   1: var sequence = new string[] { "foo", "bar" };
   2: string result = sequence.Concatenate(", ");

Now the result is “foo, bar”.

And the last one will let you specify a prefix and a suffix in addition to the separator:

   1: var sequence = new string[] { "foo", "bar" };
   2: string result = sequence.Concatenate(", ", "(", ")");

Giving you the result “(foo, bar)”. Quite neat!

Here’s the code for the extensions:

   1: /// <summary>
   2: /// Concatenates all the strings in the specified sequence.
   3: /// </summary>
   4: /// <param name="values">The values to concatenate.</param>
   5: /// <returns>The concatenated sequence.</returns>
   6: public static string Concatenate(this IEnumerable<string> values)
   7: {
   8:     return values.Concatenate(string.Empty);
   9: }
  10:  
  11: /// <summary>
  12: /// Concatenates all the strings in the specified sequence, separated by
  13: /// the specified separator.
  14: /// </summary>
  15: /// <param name="values">The values to concatenate.</param>
  16: /// <param name="separator">A string that will be inserted between all the values
  17: /// in the resulting string.</param>
  18: /// <returns>The concatenated sequence, separated by
  19: /// the specified separator.</returns>
  20: public static string Concatenate(this IEnumerable<string> values, string separator)
  21: {
  22:     return values.Concatenate(separator, string.Empty, string.Empty);
  23: }
  24:  
  25: /// <summary>
  26: /// Concatenates all the strings in the specified sequence, separated by
  27: /// the specified separator, prefixed by the value specified in <paramref name="prefix" /> and
  28: /// suffixed by the value specified in <paramref name="suffix"/>.
  29: /// </summary>
  30: /// <param name="values">The values to concatenate.</param>
  31: /// <param name="separator">A string that will be inserted between all the values
  32: /// in the resulting string.</param>
  33: /// <param name="prefix">A string that will be the start of the result string.</param>
  34: /// <param name="suffix">A string that will be the end of the result string.</param>
  35: /// <returns>The concatenated sequence, separated by
  36: /// the specified separator, prefixed by the value specified in <paramref name="prefix" /> and
  37: /// suffixed by the value specified in <paramref name="suffix"/>.</returns>
  38: public static string Concatenate(this IEnumerable<string> values, string separator, string prefix, string suffix)
  39: {
  40:     Guard.ArgumentNullException(values, "values");
  41:     Guard.ArgumentNullException(separator, "separator");
  42:     Guard.ArgumentNullException(prefix, "prefix");
  43:     Guard.ArgumentNullException(suffix, "suffix");
  44:  
  45:     var result = new StringBuilder();
  46:  
  47:     result.Append(prefix);
  48:  
  49:     foreach (var value in values)
  50:     {
  51:         if (result.Length > prefix.Length)
  52:         {
  53:             result.Append(separator);
  54:         }
  55:  
  56:         result.Append(value);
  57:     }
  58:  
  59:     result.Append(suffix);
  60:  
  61:     return result.ToString();
  62: }

… and some NUnit-tests:

   1: [TestFixture]
   2: public class sequence_of_strings_Concatenate
   3: {
   4:     string[] sequence;
   5:  
   6:     [SetUp]
   7:     public void SetUp()
   8:     {
   9:         this.OnSetUp();
  10:     }
  11:  
  12:     protected virtual void OnSetUp()
  13:     {
  14:         sequence = new string[] { "a", "b", "c" };
  15:     }
  16:  
  17:     [Test, ExpectedException(typeof(ArgumentNullException))]
  18:     public void should_throw_exception_when_sequence_is_null()
  19:     {
  20:         Legend.Collections.Collection.Concatenate(null);
  21:     }
  22:  
  23:     [Test]
  24:     public void should_concatenate_values()
  25:     {
  26:         var result = sequence.Concatenate();
  27:         Assert.AreEqual(result, "abc");
  28:     }
  29: }
  30:  
  31: [TestFixture]
  32: public class sequence_of_strings_Concatenate_with_specified_separator
  33: {
  34:     string[] sequence;
  35:  
  36:     [SetUp]
  37:     public void SetUp()
  38:     {
  39:         this.OnSetUp();
  40:     }
  41:  
  42:     protected virtual void OnSetUp()
  43:     {
  44:         sequence = new string[] { "a", "b", "c" };
  45:     }
  46:  
  47:     [Test, ExpectedException(typeof(ArgumentNullException))]
  48:     public void should_throw_exception_when_sequence_is_null()
  49:     {
  50:         Legend.Collections.Collection.Concatenate(null, ",");
  51:     }
  52:  
  53:     [Test, ExpectedException(typeof(ArgumentNullException))]
  54:     public void should_throw_exception_when_separator_is_null()
  55:     {
  56:         sequence.Concatenate(null);
  57:     }
  58:  
  59:     [Test]
  60:     public void should_concatenate_values_separated_by_separator()
  61:     {
  62:         var result = sequence.Concatenate(", ");
  63:         Assert.AreEqual(result, "a, b, c");
  64:     }
  65: }
  66:  
  67: [TestFixture]
  68: public class sequence_of_strings_Concatenate_with_specified_separator_prefix_and_suffix
  69: {
  70:     string[] sequence;
  71:  
  72:     [SetUp]
  73:     public void SetUp()
  74:     {
  75:         this.OnSetUp();
  76:     }
  77:  
  78:     protected virtual void OnSetUp()
  79:     {
  80:         sequence = new string[] { "a", "b", "c" };
  81:     }
  82:  
  83:     [Test, ExpectedException(typeof(ArgumentNullException))]
  84:     public void should_throw_exception_when_sequence_is_null()
  85:     {
  86:         Legend.Collections.Collection.Concatenate(null, ",", string.Empty, string.Empty);
  87:     }
  88:  
  89:     [Test, ExpectedException(typeof(ArgumentNullException))]
  90:     public void should_throw_exception_when_separator_is_null()
  91:     {
  92:         sequence.Concatenate(null, string.Empty, string.Empty);
  93:     }
  94:  
  95:     [Test, ExpectedException(typeof(ArgumentNullException))]
  96:     public void should_throw_exception_when_prefix_is_null()
  97:     {
  98:         sequence.Concatenate(string.Empty, null, string.Empty);
  99:     }
 100:  
 101:     [Test, ExpectedException(typeof(ArgumentNullException))]
 102:     public void should_throw_exception_when_suffix_is_null()
 103:     {
 104:         sequence.Concatenate(string.Empty, string.Empty, null);
 105:     }
 106:  
 107:     [Test]
 108:     public void should_concatenate_string_with_separator_prefix_and_suffix_appended()
 109:     {
 110:         var result = sequence.Concatenate(", ", "(", ")");
 111:         Assert.AreEqual("(a, b, c)", result);
 112:     }
 113: }

No comments:

Post a Comment