371

How can I replace multiple spaces in a string with only one space in C#?

Example:

1 2 3  4    5

would be:

1 2 3 4 5


  • a state machine can easily do it, but it's probably overkill if you need it only to remove spaces - Adrian
  • I've added a benchmark on the different ways to do this in a duplicate question stackoverflow.com/a/37592018/582061 . Regex was not the fastest way to do this. - Stian Standahl

22 답변


390

RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);     
tempo = regex.Replace(tempo, " ");


  • @Craig a comment would suffice, IMO. // This block replaces multiple spaces with one... :) - paulwhit
  • Really, RegEx is overkill for this. - Joel Coehoorn
  • But now you have 2 problems.... - seanb
  • @Joel: Can't agree. I'm actually sure that this way is more efficient than yours for large enough strings and can be done in one single line. Where's the overkill? - Konrad Rudolph
  • @Oscar Joel’s code isn’t a simple loop through all characters! It’s a hidden nested loop that has a quadratic worst case. This regular expression, by contrast, is linear, only builds up a single string (= drastically reduced allocation costs compared to Joel’s code) and furthermore the engine can optimize the hell out of it (to be honest, I doubt the .NET regex is smart enough for this but in theory this regular expression can be implemented so cheaply that it’s not even funny any more; it only needs a DFA with three states, one transition each, and no additional information). - Konrad Rudolph

538

I like to use:

myString = Regex.Replace(myString, @"\s+", " ");

Since it will catch runs of any kind of whitespace (e.g. tabs, newlines, etc.) and replace them with a single space.


  • Slight modification: Regex.Replace(source, @"(\s)\s+", "$1"); This will return the first whitespace type found. So if you have 5 tabs, it will return a tab. Incase someone prefers this. - F.B. ten Kate
  • @radistao Your link is for Javascript string replace, not for C#. - Shiva
  • @Shiva, /\s\s+/ is a standard POSIX regex statement and may be converted/used in any language using own syntax - radistao
  • @F.B.tenKate Good option. A further example is if you have tab-space-space-tab-newline, it will return a tab. - goodeye
  • In the spirit of @F.B.tenKate's solution: Regex.Replace(source, @"(\s)\1+", "$1"); will replace multiple identical consecutive characters by a single one. - François Beaune

38

string xyz = "1   2   3   4   5";
xyz = string.Join( " ", xyz.Split( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries ));


  • Regex works too. - tvanfosson
  • This is more readable over regex, i prefer it more because i don't need to learn some other syntax - Michael Bahig
  • I like it because it doesnt need Regex - AleX_
  • This would be inefficient for large strings. - DarcyThomas
  • This also removes leading and trailing spaces. - Matzi

37

I think Matt's answer is the best, but I don't believe it's quite right. If you want to replace newlines, you must use:

myString = Regex.Replace(myString, @"\s+", " ", RegexOptions.Multiline);


  • RegexOptions.Multiline changes the meaning of ^ and $ so they match the beginning and end of every line ($ = \n), instead of the whole multi-line string. Because \s is equivalent to [ \f\n\r\t\v] the newlines should be replaced even if Multiline option is off. - SushiGuy
  • Matt's answer has already covered this. I 'believe' 30 persons just blindfold up-voted this answer :) - 123iamking

21

Another approach which uses LINQ:

 var list = str.Split(' ').Where(s => !string.IsNullOrWhiteSpace(s));
 str = string.Join(" ", list);


21

It's much simpler than all that:

while(str.Contains("  ")) str = str.Replace("  ", " ");


  • This will be far less efficient than the regex " {2,}" if the string contains sequences of 3 or more spaces. - Jan Goyvaerts
  • @JanGoyvaerts: Even with 10 spaces, the regex was slower when I made a quick and dirty test. That being said, it only takes one giant substring full of spaces to completely kill performance of the while loop. For fairness, I used I used RegexOptions.Compiled, rather than the slower Regex.Replace. - Brian
  • RegexOptions.Compiled adds a lot of overhead compiling the regex into IL. Don't use it unless your application will use the regex often enough or on large enough strings that the increased matching speed offsets the decreased compilation speed. - Jan Goyvaerts

14

myString = Regex.Replace(myString, " {2,}", " ");


19

Regex can be rather slow even with simple tasks. This creates an extension method that can be used off of any string.

    public static class StringExtension
    {
        public static String ReduceWhitespace(this String value)
        {
            var newString = new StringBuilder();
            bool previousIsWhitespace = false;
            for (int i = 0; i < value.Length; i++)
            {
                if (Char.IsWhiteSpace(value[i]))
                {
                    if (previousIsWhitespace)
                    {
                        continue;
                    }

                    previousIsWhitespace = true;
                }
                else
                {
                    previousIsWhitespace = false;
                }

                newString.Append(value[i]);
            }

            return newString.ToString();
        }
    }

It would be used as such:

string testValue = "This contains     too          much  whitespace."
testValue = testValue.ReduceWhitespace();
// testValue = "This contains too much whitespace."


8

For those, who don't like Regex, here is a method that uses the StringBuilder:

    public static string FilterWhiteSpaces(string input)
    {
        if (input == null)
            return string.Empty;

        StringBuilder stringBuilder = new StringBuilder(input.Length);
        for (int i = 0; i < input.Length; i++)
        {
            char c = input[i];
            if (i == 0 || c != ' ' || (c == ' ' && input[i - 1] != ' '))
                stringBuilder.Append(c);
        }
        return stringBuilder.ToString();
    }

In my tests, this method was 16 times faster on average with a very large set of small-to-medium sized strings, compared to a static compiled Regex. Compared to a non-compiled or non-static Regex, this should be even faster.

Keep in mind, that it does not remove leading or trailing spaces, only multiple occurrences of such.



8

You can simply do this in one line solution!

string s = "welcome to  london";
s.Replace(" ", "()").Replace(")(", "").Replace("()", " ");

You can choose other brackets (or even other characters) if you like.


  • You have to make sure your string doesn't have "()" or ")(" in it. Or "wel()come to london)(" becomes "wel come to london". You could try using lots of brackets. So use ((((())))) instead of () and )))))((((( instead of )(. It will still work. Still, if the string contains ((((())))) or )))))(((((, this will fail. - nmit026

5

This is a shorter version, which should only be used if you are only doing this once, as it creates a new instance of the Regex class every time it is called.

temp = new Regex(" {2,}").Replace(temp, " "); 

If you are not too acquainted with regular expressions, here's a short explanation:

The {2,} makes the regex search for the character preceding it, and finds substrings between 2 and unlimited times.
The .Replace(temp, " ") replaces all matches in the string temp with a space.

If you want to use this multiple times, here is a better option, as it creates the regex IL at compile time:

Regex singleSpacify = new Regex(" {2,}", RegexOptions.Compiled);
temp = singleSpacify.Replace(temp, " ");


5

no Regex, no Linq... removes leading and trailing spaces as well as reducing any embedded multiple space segments to one space

string myString = "   0 1 2  3   4               5  ";
myString = string.Join(" ", myString.Split(new char[] { ' ' }, 
StringSplitOptions.RemoveEmptyEntries));

result:"0 1 2 3 4 5"


  • A word of caution : The use of split, while very simple to understand indeed, can have surprisingly negative performance impact. As many strings could be created, you'll have to watch your memory usage in case you handle large strings with this method. - Pac0

4

Consolodating other answers, per Joel, and hopefully improving slightly as I go:

You can do this with Regex.Replace():

string s = Regex.Replace (
    "   1  2    4 5", 
    @"[ ]{2,}", 
    " "
    );

Or with String.Split():

static class StringExtensions
{
    public static string Join(this IList<string> value, string separator)
    {
        return string.Join(separator, value.ToArray());
    }
}

//...

string s = "     1  2    4 5".Split (
    " ".ToCharArray(), 
    StringSplitOptions.RemoveEmptyEntries
    ).Join (" ");


2

I just wrote a new Join that I like, so I thought I'd re-answer, with it:

public static string Join<T>(this IEnumerable<T> source, string separator)
{
    return string.Join(separator, source.Select(e => e.ToString()).ToArray());
}

One of the cool things about this is that it work with collections that aren't strings, by calling ToString() on the elements. Usage is still the same:

//...

string s = "     1  2    4 5".Split (
    " ".ToCharArray(), 
    StringSplitOptions.RemoveEmptyEntries
    ).Join (" ");


  • why create an extension method? why not just use string.Join()? - Eric Schoonover

2

I know this is pretty old, but ran across this while trying to accomplish almost the same thing. Found this solution in RegEx Buddy. This pattern will replace all double spaces with single spaces and also trim leading and trailing spaces.

pattern: (?m:^ +| +$|( ){2,})
replacement: $1

Its a little difficult to read since we're dealing with empty space, so here it is again with the "spaces" replaced with a "_".

pattern: (?m:^_+|_+$|(_){2,})  <-- don't use this, just for illustration.

The "(?m:" construct enables the "multi-line" option. I generally like to include whatever options I can within the pattern itself so it is more self contained.


1

I can remove whitespaces with this

while word.contains("  ")  //double space
   word = word.Replace("  "," "); //replace double space by single space.
word = word.trim(); //to remove single whitespces from start & end.


  • yes but you would only replace two whitespaces with one. This would not help X number of spaces - MGot90
  • That While loop will take care of all that double spaces to be removed. - Learner1947

1

Many answers are providing the right output but for those looking for the best performances, I did improve Nolanar's answer (which was the best answer for performance) by about 10%.

public static string MergeSpaces(this string str)
{

    if (str == null)
    {
        return null;
    }
    else
    {
        StringBuilder stringBuilder = new StringBuilder(str.Length);

        int i = 0;
        foreach (char c in str)
        {
            if (c != ' ' || i == 0 || str[i - 1] != ' ')
                stringBuilder.Append(c);
            i++;
        }
        return stringBuilder.ToString();
    }

}


1

try this method

private string removeNestedWhitespaces(char[] st)
{
    StringBuilder sb = new StringBuilder();
    int indx = 0, length = st.Length;
    while (indx < length)
    {
        sb.Append(st[indx]);
        indx++;
        while (indx < length && st[indx] == ' ')
            indx++;
        if(sb.Length > 1  && sb[0] != ' ')
            sb.Append(' ');
    }
    return sb.ToString();
}

use it like this:

string test = removeNestedWhitespaces("1 2 3  4    5".toCharArray());


  • This will remove the trailing spaces - The_Black_Smurf
  • sorry for the mistake, i fixed the code, now it's work as expected tested string: " 1 2 3 4 9 " result string: " 1 2 3 4 9 " - Ahmed Aljaff

0

Old skool:

string oldText = "   1 2  3   4    5     ";
string newText = oldText
                    .Replace("  ", " " + (char)22 )
                    .Replace( (char)22 + " ", "" )
                    .Replace( (char)22 + "", "" );

Assert.That( newText, Is.EqualTo( " 1 2 3 4 5 " ) );


  • Assumes text does not already contain (char)22 - onedaywhen

0

Without using regular expressions:

while (myString.IndexOf("  ", StringComparison.CurrentCulture) != -1)
{
    myString = myString.Replace("  ", " ");
}

OK to use on short strings, but will perform badly on long strings with lots of spaces.


0

Use the regex pattern

    [ ]+    #only space

   var text = Regex.Replace(inputString, @"[ ]+", " ");


0

Mix of StringBuilder and Enumerable.Aggregate() as extension method for strings:

using System;
using System.Linq;
using System.Text;

public static class StringExtension
{
    public static string StripSpaces(this string s)
    {
        return s.Aggregate(new StringBuilder(), (acc, c) =>
        {
            if (c != ' ' || acc.Length > 0 && acc[acc.Length-1] != ' ')
                acc.Append(c);

            return acc;
        }).ToString();
    }

    public static void Main()
    {
        Console.WriteLine("\"" + StringExtension.StripSpaces("1   Hello       World  2   ") + "\"");
    }
}

Input:

"1   Hello       World  2   "

Output:

"1 Hello World 2 "

Linked


Related

Latest