10
\$\begingroup\$

My implementation:

string ReplaceAllSpaces(string input)
{
    StringBuilder builder = new StringBuilder();
    using(StringReader reader = new StringReader(input))
    {
        while(reader.Peek() != -1)
        {
            char c = (char)reader.Peek();
            if(char.IsWhiteSpace(c))
            {
                while(char.IsWhiteSpace(c)) 
                { 
                    reader.Read(); 
                    c = (char)reader.Peek();
                } 
                builder.Append("%20");
            }
            else builder.Append((char)reader.Read()); 
        }
    }
    return builder.ToString();
}

Input:

"My      Name Is  John"

Output:

"My%20Name%20Is%20John"

How could this be improved? Only ASCII characters are permitted.

\$\endgroup\$
10
  • 7
    \$\begingroup\$ Is there something you're trying to accomplish that input.Replace(" ", "%20"); won't? \$\endgroup\$
    – Comintern
    Commented Oct 7, 2014 at 0:11
  • 7
    \$\begingroup\$ This replaces several consecutive spaces with a single %20. Is this the desired behaviour? Usually each space would be replaced by a single %20. \$\endgroup\$
    – mjolka
    Commented Oct 7, 2014 at 0:23
  • 1
    \$\begingroup\$ @mjolka Yes. I'll add some more information to the question. \$\endgroup\$ Commented Oct 7, 2014 at 0:25
  • 2
    \$\begingroup\$ Is there a problem with UrlEncode() ? Gets all non-roman characters, not just spaces. \$\endgroup\$
    – paul
    Commented Oct 7, 2014 at 13:24
  • 1
    \$\begingroup\$ Are you certain that it's only spaces you need to escape as percent-encoded characters? There are other characters besides spaces which need to be precent-encoded when used in a URL: en.wikipedia.org/wiki/… (If you need to escape these characters too, it's probably a good idea to use a library.) \$\endgroup\$
    – Ajedi32
    Commented Oct 7, 2014 at 13:44

2 Answers 2

40
\$\begingroup\$

This one really fits well for a regular expression:

public static string ReplaceAllSpaces(string str) {
  return Regex.Replace(str, @"\s+","%20");
}

The expression \s+ consists of the pattern \s that matches a whitespace character (which is more that just spaces, as noted by @tinstaafl), and the quantifier + which means "at least once".

The pattern matches "one or more whitespace characters", so it will match each group of whitespace characters (for example the six spaces between My and Name in the example) and replace it with %20.

\$\endgroup\$
6
  • 5
    \$\begingroup\$ This is what Regexes were made for. \$\endgroup\$
    – Mark
    Commented Oct 7, 2014 at 6:13
  • \$\begingroup\$ The only correct answer in my opinion. No need to write lines of code for something which can be done in such a simple way. =) \$\endgroup\$
    – Abbas
    Commented Oct 7, 2014 at 13:06
  • \$\begingroup\$ would you please explain for OP how this does exactly the same as his code but is much better? I always have to look up Regex if I need to use it, so does your code replace 5 spaces with one %20 or does it replace them with %20%20%20%20%20 \$\endgroup\$
    – Malachi
    Commented Oct 7, 2014 at 14:43
  • 2
    \$\begingroup\$ @Malachi: this is a very simple regex. It is composed of a pattern and a quantifier. the pattern is \s, or whitespaces (btw, this englobes much more that just spaces, as noted by @tinstaafl), and the quantifier is +, which is at least once. \$\endgroup\$
    – njzk2
    Commented Oct 7, 2014 at 14:46
  • 1
    \$\begingroup\$ @njzk2: Thanks for the suggested edit. I used most of it (just wanted to put it in my own words), and added an example from the data in the question. \$\endgroup\$
    – Guffa
    Commented Oct 7, 2014 at 15:12
6
\$\begingroup\$

Since a string is basically a character array, I would do away with the stringreader and simply loop through the string itself:

    static string ReplaceAllSpaces(string input)
    {
        StringBuilder builder = new StringBuilder();
        bool continuousSpace = false;
        foreach (char c in input)
        {
            if (!continuousSpace && char.IsWhiteSpace(c))
            {
                builder.Append("%20");
                continuousSpace = true;
            }
            else if(!char.IsWhiteSpace(c))
            {
                builder.Append(c);
                continuousSpace = false;
            }
        }
        return builder.ToString();
    }

A side note: Whitespace includes a lot of other characters in the unicode set as well as the space.

White space characters are the following Unicode characters:

Members of the SpaceSeparator category, which includes the characters

SPACE (U+0020), OGHAM SPACE MARK (U+1680), MONGOLIAN VOWEL SEPARATOR (U+180E), EN QUAD (U+2000), EM QUAD (U+2001), EN SPACE (U+2002), EM SPACE (U+2003), THREE-PER-EM SPACE (U+2004), FOUR-PER-EM SPACE (U+2005), SIX-PER-EM SPACE (U+2006), FIGURE SPACE (U+2007), PUNCTUATION SPACE (U+2008), THIN SPACE (U+2009), HAIR SPACE (U+200A), NARROW NO-BREAK SPACE (U+202F), MEDIUM MATHEMATICAL SPACE (U+205F), and IDEOGRAPHIC SPACE (U+3000).

Members of the LineSeparator category, which consists solely of the LINE SEPARATOR character (U+2028).

Members of the ParagraphSeparator category, which consists solely of the PARAGRAPH SEPARATOR character (U+2029).

The characters CHARACTER TABULATION (U+0009), LINE FEED (U+000A), LINE TABULATION (U+000B), FORM FEED (U+000C), CARRIAGE RETURN (U+000D), NEXT LINE (U+0085), and NO-BREAK SPACE (U+00A0).

\$\endgroup\$
2
  • \$\begingroup\$ Let's ignore Unicode for now. \$\endgroup\$ Commented Oct 7, 2014 at 1:18
  • 6
    \$\begingroup\$ The whitespace category will still include those character codes that are considered ASCII(9,10,11,12,13,32, etc.) \$\endgroup\$
    – user33306
    Commented Oct 7, 2014 at 1:21

Not the answer you're looking for? Browse other questions tagged or ask your own question.