Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 106737
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 11, 20262026-05-11T01:38:38+00:00 2026-05-11T01:38:38+00:00

I’ve been tinkering with small functions on my own time, trying to find ways

  • 0

I’ve been tinkering with small functions on my own time, trying to find ways to refactor them (I recently read Martin Fowler’s book Refactoring: Improving the Design of Existing Code). I found the following function MakeNiceString() while updating another part of the codebase near it, and it looked like a good candidate to mess with. As it is, there’s no real reason to replace it, but it’s small enough and does something small so it’s easy to follow and yet still get a ‘good’ experience from.

private static string MakeNiceString(string str)         {             char[] ca = str.ToCharArray();             string result = null;             int i = 0;             result += System.Convert.ToString(ca[0]);             for (i = 1; i <= ca.Length - 1; i++)             {                 if (!(char.IsLower(ca[i])))                 {                     result += ' ';                 }                 result += System.Convert.ToString(ca[i]);             }             return result;         }   static string SplitCamelCase(string str)     {         string[] temp = Regex.Split(str, @'(?<!^)(?=[A-Z])');         string result = String.Join(' ', temp);         return result;     } 

The first function MakeNiceString() is the function I found in some code I was updating at work. The purpose of the function is to translate ThisIsAString to This Is A String. It’s used in a half-dozen places in the code, and is pretty insignificant in the whole scheme of things.

I built the second function purely as an academic exercise to see if using a regular expression would take longer or not.

Well, here are the results:

With 10 Iterations:

 MakeNiceString took 2649 ticks SplitCamelCase took 2502 ticks 

However, it changes drastically over the longhaul:

With 10,000 Iterations:

 MakeNiceString took 121625 ticks SplitCamelCase took 443001 ticks 

Refactoring MakeNiceString()

The process of refactoring MakeNiceString() started with simply removing the conversions that were taking place. Doing that yielded the following results:

 MakeNiceString took 124716 ticks ImprovedMakeNiceString took 118486 

Here’s the code after Refactor #1:

private static string ImprovedMakeNiceString(string str)         { //Removed Convert.ToString()             char[] ca = str.ToCharArray();             string result = null;             int i = 0;             result += ca[0];             for (i = 1; i <= ca.Length - 1; i++)             {                 if (!(char.IsLower(ca[i])))                 {                     result += ' ';                 }                 result += ca[i];             }             return result;         } 

Refactor#2 – Use StringBuilder

My second task was to use StringBuilder instead of String. Since String is immutable, unnecessary copies were being created throughout the loop. The benchmark for using that is below, as is the code:

static string RefactoredMakeNiceString(string str)         {             char[] ca = str.ToCharArray();             StringBuilder sb = new StringBuilder((str.Length * 5 / 4));             int i = 0;             sb.Append(ca[0]);             for (i = 1; i <= ca.Length - 1; i++)             {                 if (!(char.IsLower(ca[i])))                 {                     sb.Append(' ');                 }                 sb.Append(ca[i]);             }             return sb.ToString();         } 

This results in the following Benchmark:

 MakeNiceString Took:           124497 Ticks   //Original SplitCamelCase Took:           464459 Ticks   //Regex ImprovedMakeNiceString Took:   117369 Ticks   //Remove Conversion RefactoredMakeNiceString Took:  38542 Ticks   //Using StringBuilder 

Changing the for loop to a foreach loop resulted in the following benchmark result:

static string RefactoredForEachMakeNiceString(string str)         {             char[] ca = str.ToCharArray();             StringBuilder sb1 = new StringBuilder((str.Length * 5 / 4));             sb1.Append(ca[0]);             foreach (char c in ca)             {                 if (!(char.IsLower(c)))                 {                     sb1.Append(' ');                 }                 sb1.Append(c);             }             return sb1.ToString();         } 
 RefactoredForEachMakeNiceString    Took:  45163 Ticks 

As you can see, maintenance-wise, the foreach loop will be the easiest to maintain and have the ‘cleanest’ look. It is slightly slower than the for loop, but infinitely easier to follow.

Alternate Refactor: Use Compiled Regex

I moved the Regex to right before the loop is begun, in hopes that since it only compiles it once, it’ll execute faster. What I found out (and I’m sure I have a bug somewhere) is that that doesn’t happen like it ought to:

static void runTest5()         {             Regex rg = new Regex(@'(?<!^)(?=[A-Z])', RegexOptions.Compiled);             for (int i = 0; i < 10000; i++)             {                 CompiledRegex(rg, myString);             }         }  static string CompiledRegex(Regex regex, string str)     {         string result = null;         Regex rg1 = regex;         string[] temp = rg1.Split(str);         result = String.Join(' ', temp);         return result;     } 

Final Benchmark Results:

 MakeNiceString Took                   139363 Ticks SplitCamelCase Took                   489174 Ticks ImprovedMakeNiceString Took           115478 Ticks RefactoredMakeNiceString Took          38819 Ticks RefactoredForEachMakeNiceString Took   44700 Ticks CompiledRegex Took                    227021 Ticks 

Or, if you prefer milliseconds:

 MakeNiceString Took                  38 ms SplitCamelCase Took                 123 ms ImprovedMakeNiceString Took          33 ms RefactoredMakeNiceString Took        11 ms RefactoredForEachMakeNiceString Took 12 ms CompiledRegex Took                   63 ms 

So the percentage gains are:

 MakeNiceString                   38 ms   Baseline SplitCamelCase                  123 ms   223% slower ImprovedMakeNiceString           33 ms   13.15% faster RefactoredMakeNiceString         11 ms   71.05% faster RefactoredForEachMakeNiceString  12 ms   68.42% faster CompiledRegex                    63 ms   65.79% slower 

(Please check my math)

In the end, I’m going to replace what’s there with the RefactoredForEachMakeNiceString() and while I’m at it, I’m going to rename it to something useful, like SplitStringOnUpperCase.

Benchmark Test:

To benchmark, I simply invoke a new Stopwatch for each method call:

       string myString = 'ThisIsAUpperCaseString';        Stopwatch sw = new Stopwatch();        sw.Start();        runTest();        sw.Stop();       static void runTest()         {              for (int i = 0; i < 10000; i++)             {                 MakeNiceString(myString);             }           } 

Questions

  • What causes these functions to be so different ‘over the long haul’, and
  • How can I improve this function a) to be more maintainable or b) to run faster?
  • How would I do memory benchmarks on these to see which used less memory?

Thank you for your responses thus far. I’ve inserted all of the suggestions made by @Jon Skeet, and would like feedback on the updated questions I’ve asked as a result.

NB: This question is meant to explore ways to refactor string handling functions in C#. I copied/pasted the first code as is. I’m well aware you can remove the System.Convert.ToString() in the first method, and I did just that. If anyone is aware of any implications of removing the System.Convert.ToString(), that would also be helpful to know.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. 2026-05-11T01:38:38+00:00Added an answer on May 11, 2026 at 1:38 am

    1) Use a StringBuilder, preferrably set with a reasonable initial capacity (e.g. string length * 5/4, to allow one extra space per four characters).

    2) Try using a foreach loop instead of a for loop – it may well be simpler

    3) You don’t need to convert the string into a char array first – foreach will work over a string already, or use the indexer.

    4) Don’t do extra string conversions everywhere – calling Convert.ToString(char) and then appending that string is pointless; there’s no need for the single character string

    5) For the second option, just build the regex once, outside the method. Try it with RegexOptions.Compiled as well.

    EDIT: Okay, full benchmark results. I’ve tried a few more things, and also executed the code with rather more iterations to get a more accurate result. This is only running on an Eee PC, so no doubt it’ll run faster on ‘real’ PCs, but I suspect the broad results are appropriate. First the code:

    using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions;  class Benchmark {     const string TestData = 'ThisIsAUpperCaseString';     const string ValidResult = 'This Is A Upper Case String';     const int Iterations = 1000000;      static void Main(string[] args)     {         Test(BenchmarkOverhead);         Test(MakeNiceString);         Test(ImprovedMakeNiceString);         Test(RefactoredMakeNiceString);         Test(MakeNiceStringWithStringIndexer);         Test(MakeNiceStringWithForeach);         Test(MakeNiceStringWithForeachAndLinqSkip);         Test(MakeNiceStringWithForeachAndCustomSkip);         Test(SplitCamelCase);         Test(SplitCamelCaseCachedRegex);         Test(SplitCamelCaseCompiledRegex);             }      static void Test(Func<string,string> function)     {         Console.Write('{0}... ', function.Method.Name);         Stopwatch sw = Stopwatch.StartNew();         for (int i=0; i < Iterations; i++)         {             string result = function(TestData);             if (result.Length != ValidResult.Length)             {                 throw new Exception('Bad result: ' + result);             }         }         sw.Stop();         Console.WriteLine(' {0}ms', sw.ElapsedMilliseconds);         GC.Collect();     }      private static string BenchmarkOverhead(string str)     {         return ValidResult;     }      private static string MakeNiceString(string str)     {         char[] ca = str.ToCharArray();         string result = null;         int i = 0;         result += System.Convert.ToString(ca[0]);         for (i = 1; i <= ca.Length - 1; i++)         {             if (!(char.IsLower(ca[i])))             {                 result += ' ';             }             result += System.Convert.ToString(ca[i]);         }         return result;     }      private static string ImprovedMakeNiceString(string str)     { //Removed Convert.ToString()         char[] ca = str.ToCharArray();         string result = null;         int i = 0;         result += ca[0];         for (i = 1; i <= ca.Length - 1; i++)         {             if (!(char.IsLower(ca[i])))             {                 result += ' ';             }             result += ca[i];         }         return result;     }      private static string RefactoredMakeNiceString(string str)     {         char[] ca = str.ToCharArray();         StringBuilder sb = new StringBuilder((str.Length * 5 / 4));         int i = 0;         sb.Append(ca[0]);         for (i = 1; i <= ca.Length - 1; i++)         {             if (!(char.IsLower(ca[i])))             {                 sb.Append(' ');             }             sb.Append(ca[i]);         }         return sb.ToString();     }      private static string MakeNiceStringWithStringIndexer(string str)     {         StringBuilder sb = new StringBuilder((str.Length * 5 / 4));         sb.Append(str[0]);         for (int i = 1; i < str.Length; i++)         {             char c = str[i];             if (!(char.IsLower(c)))             {                 sb.Append(' ');             }             sb.Append(c);         }         return sb.ToString();     }      private static string MakeNiceStringWithForeach(string str)     {         StringBuilder sb = new StringBuilder(str.Length * 5 / 4);         bool first = true;               foreach (char c in str)         {             if (!first && char.IsUpper(c))             {                 sb.Append(' ');             }             sb.Append(c);             first = false;         }         return sb.ToString();     }      private static string MakeNiceStringWithForeachAndLinqSkip(string str)     {         StringBuilder sb = new StringBuilder(str.Length * 5 / 4);         sb.Append(str[0]);         foreach (char c in str.Skip(1))         {             if (char.IsUpper(c))             {                 sb.Append(' ');             }             sb.Append(c);         }         return sb.ToString();     }      private static string MakeNiceStringWithForeachAndCustomSkip(string str)     {         StringBuilder sb = new StringBuilder(str.Length * 5 / 4);         sb.Append(str[0]);         foreach (char c in new SkipEnumerable<char>(str, 1))         {             if (char.IsUpper(c))             {                 sb.Append(' ');             }             sb.Append(c);         }         return sb.ToString();     }      private static string SplitCamelCase(string str)     {         string[] temp = Regex.Split(str, @'(?<!^)(?=[A-Z])');         string result = String.Join(' ', temp);         return result;     }      private static readonly Regex CachedRegex = new Regex('(?<!^)(?=[A-Z])');         private static string SplitCamelCaseCachedRegex(string str)     {         string[] temp = CachedRegex.Split(str);         string result = String.Join(' ', temp);         return result;     }      private static readonly Regex CompiledRegex =         new Regex('(?<!^)(?=[A-Z])', RegexOptions.Compiled);         private static string SplitCamelCaseCompiledRegex(string str)     {         string[] temp = CompiledRegex.Split(str);         string result = String.Join(' ', temp);         return result;     }      private class SkipEnumerable<T> : IEnumerable<T>     {         private readonly IEnumerable<T> original;         private readonly int skip;          public SkipEnumerable(IEnumerable<T> original, int skip)         {             this.original = original;             this.skip = skip;         }          public IEnumerator<T> GetEnumerator()         {             IEnumerator<T> ret = original.GetEnumerator();             for (int i=0; i < skip; i++)             {                 ret.MoveNext();             }             return ret;         }          IEnumerator IEnumerable.GetEnumerator()         {             return GetEnumerator();         }     } } 

    Now the results:

    BenchmarkOverhead...  22ms MakeNiceString...  10062ms ImprovedMakeNiceString...  12367ms RefactoredMakeNiceString...  3489ms MakeNiceStringWithStringIndexer...  3115ms MakeNiceStringWithForeach...  3292ms MakeNiceStringWithForeachAndLinqSkip...  5702ms MakeNiceStringWithForeachAndCustomSkip...  4490ms SplitCamelCase...  68267ms SplitCamelCaseCachedRegex...  52529ms SplitCamelCaseCompiledRegex...  26806ms 

    As you can see, the string indexer version is the winner – it’s also pretty simple code.

    Hope this helps… and don’t forget, there are bound to be other options I haven’t thought of!

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Ask A Question

Stats

  • Questions 77k
  • Answers 77k
  • Best Answers 0
  • User 1
  • Popular
  • Answers
  • Editorial Team

    How to approach applying for a job at a company ...

    • 7 Answers
  • Editorial Team

    How to handle personal stress caused by utterly incompetent and ...

    • 5 Answers
  • Editorial Team

    What is a programmer’s life like?

    • 5 Answers
  • added an answer Yep, set the blend for the Brush. LinearGradientBrush blendBrush =… May 11, 2026 at 3:20 pm
  • added an answer Server side: Read the website f.ex every minute and save… May 11, 2026 at 3:20 pm
  • added an answer For the '/#{path}/Default.aspx' part, use: Page.ResolveUrl('~/Default.aspx') If you need more:… May 11, 2026 at 3:20 pm

Related Questions

I ran into a problem. Wrote the following code snippet: teksti = teksti.Trim() teksti
I am currently running into a problem where an element is coming back from
Seemingly simple, but I cannot find anything relevant on the web. What is the
Configuring TinyMCE to allow for tags, based on a customer requirement. My config is
Is it possible to replace javascript w/ HTML if JavaScript is not enabled on

Trending Tags

analytics british company computer developers django employee employer english facebook french google interview javascript language life php programmer programs salary

Top Members

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.