tags:

views:

99

answers:

3

Hello,

let's say I have the following string:

string s = "A B  C   D    TESTTEST  BLA BLA      TEST       TEST2"

Then I need the following:

"A B  C   D    TESTTEST  BLA BLA      TEST       TEST2"

So the rules are:
a) replace every second space (between non space chars) with  
b) If the last space is replaced with  , try to move it backwards (if possible) one step so the next word is not touched by the force space.

Background:

I want to use that to print data from the database to my website. But I want to optimize the forced spaces to use less space. I also want the last forced space not to touch the next word (if possible) so it is easier for some search engines to catch that word.

Will I need to loop through every char in that string and count the occurrence or is there an easier, faster and more fancy way?

Thank you, both solutions are working perfect.
So I did a benchmark to figure out which solution to accept:

@Guffa, your solution needs 22 seconds for 1 Million runs
@Timwi, your solution needs 7 seconds for 1 Million runs

I will give you both an upvote, but I will accept Timwi's solution.

+1  A: 

You can do like this:

s = String.Concat(
  Regex.Split(s, "( +)")
  .Select((p, i) => i % 2 == 0 ? p :
    String.Concat(
      Enumerable.Repeat(" &nbsp;", p.Length<3 ? p.Length-1 : p.Length/2-1)
      .ToArray()) +
    (p.Length % 2 == 1 ? " " : "") +
    (p.Length > 2 ? "&nbsp; " : ""))
  .ToArray()
);
Guffa
Why the downvote?
Guffa
No idea, wasn’t me! It certainly works (I tried it)...
Timwi
Damn annoying downvoters, they never leave a comment. +1 to correct it.
Callum Rogers
The downvote wasn't from me either. I will try your solution now.
Chris
+4  A: 

Let’s use a regular expression!

var input = "A B  C   D    TESTTEST  BLA BLA      TEST       TEST2";
var output = Regex.Replace(input, @"  +", m =>
    m.Length == 2 ? " &nbsp;" :
    m.Length % 2 == 1 ? " &nbsp;".Repeat(m.Length / 2) + " " :
    " &nbsp;".Repeat(m.Length / 2 - 1) + "&nbsp; ");

This uses a string.Repeat extension method I wrote:

/// <summary>
/// Concatenates the specified number of repetitions of the current string.
/// </summary>
/// <param name="input">The string to be repeated.</param>
/// <param name="numTimes">The number of times to repeat the string.</param>
/// <returns>A concatenated string containing the original string the specified number of times.</returns>
public static string Repeat(this string input, int numTimes)
{
    if (numTimes == 0) return "";
    if (numTimes == 1) return input;
    if (numTimes == 2) return input + input;
    var sb = new StringBuilder();
    for (int i = 0; i < numTimes; i++)
        sb.Append(input);
    return sb.ToString();
}

By the way, if by “saving space” you are referring to bandwidth / storage space, you can make this even more compact by using "\xa0" instead of "&nbsp;", which is equivalent in HTML.

Timwi
+1: I never new about using a `MatchEvaluator`! Learn something new everyday...
Callum Rogers
A: 
s.Replace("  ", " &nbsp;");
wraithx2