Como substituo vários espaços por um único espaço em c #?

439

Como posso substituir vários espaços em uma seqüência de caracteres por apenas um espaço em C #?

Exemplo:

1 2 3  4    5

seria:

1 2 3 4 5
Pokus
fonte
1
uma máquina de estado pode facilmente fazê-lo, mas é provavelmente um exagero se você precisar dele apenas para remover os espaços
Adrian
Adicionei uma referência sobre as diferentes maneiras de fazer isso em uma pergunta duplicada stackoverflow.com/a/37592018/582061 . Regex não era a maneira mais rápida de fazer isso.
perfil completo de Stian Standahl

Respostas:

468
string sentence = "This is a sentence with multiple    spaces";
RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);     
sentence = regex.Replace(sentence, " ");
Patrick Desjardins
fonte
2
Tenho copiar e colar isso e funciona. Realmente não gosto do REgex, mas desta vez ele salva minha vida.
Pokus 15/10/08
9
@ Craig um comentário seria suficiente, IMO. // Este bloco substitui vários espaços por um ... :) #
paulwhit
6
Realmente, o RegEx é um exagero para isso.
Joel Coehoorn
11
@ Joel: Não posso concordar. Na verdade, tenho certeza de que esse caminho é mais eficiente que o seu para seqüências grandes o suficiente e pode ser feito em uma única linha. Onde está o exagero?
21978 Konrad Rudolph
24
O código de @Oscar Joel não é um loop simples em todos os personagens! É um loop aninhado oculto que tem um pior caso quadrático. Essa expressão regular, por outro lado, é linear, apenas cria uma única string (= custos de alocação drasticamente reduzidos em comparação com o código de Joel) e, além disso, o mecanismo pode otimizar o inferno (para ser sincero, duvido que o regex .NET seja inteligente o suficiente para isso, mas, em teoria, essa expressão regular pode ser implementada tão barata que nem sequer é mais engraçada; ela precisa apenas de um DFA com três estados, uma transição cada e sem informações adicionais).
Konrad Rudolph
623

Eu gosto de usar:

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

Uma vez que ele captura execuções de qualquer tipo de espaço em branco (por exemplo, guias, novas linhas etc.) e as substitui por um único espaço.

Matt
fonte
43
Ligeira modificação: Regex.Replace (origem, @ "(\ s) \ s +", "$ 1"); Isso retornará o primeiro tipo de espaço em branco encontrado. Portanto, se você tiver 5 guias, ele retornará uma guia. Caso alguém prefira isso.
FB ten Kate
@radistao Seu link é para substituição de string Javascript, não para C #.
Shiva
1
@Shiva, / \ s \ s + / é uma declaração POSIX regex padrão e pode ser convertido / utilizado em qualquer idioma usando própria sintaxe
radistao
4
No espírito da solução da @ FBtenKate: Regex.Replace (source, @ "(\ s) \ 1+", "$ 1"); substituirá vários caracteres consecutivos idênticos por um único.
François Beaune
1
para remover os espaços em branco iniciais e finais, você deve usar a função Trim () com isso, como var myString = Regex.Replace (myString, @ "\ s +", "") .Trim ();
quer
50
string xyz = "1   2   3   4   5";
xyz = string.Join( " ", xyz.Split( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries ));
tvanfosson
fonte
6
Esta é mais legível sobre regex, eu preferi-lo mais, porque eu não preciso de aprender alguma outra sintaxe
Michael Bahig
9
Eu gosto dele porque ele não precisa Regex
AleX_
3
Isso seria ineficiente para cadeias grandes.
DarcyThomas 28/09
3
Isso também remove os espaços iniciais e finais.
Matzi 5/02
1
Eu prefiro essa resposta também. Meu antigo mentor usado para dizer "quando você tem um problema que você acha que precisa de Regex para resolver, bem ... agora você tem dois problemas" <piscadela>
William Madonna Jr.
38

Acho que a resposta de Matt é a melhor, mas não acredito que esteja certa. Se você deseja substituir novas linhas, você deve usar:

myString = Regex.Replace(myString, @"\s+", " ", RegexOptions.Multiline);
Brenda Bell
fonte
4
RegexOptions.Multiline altera o significado de ^ e $ para que correspondam ao início e ao final de cada linha ($ = \ n), em vez de toda a sequência de várias linhas. Como \ s é equivalente a [\ f \ n \ r \ t \ v], as novas linhas devem ser substituídas mesmo se a opção Multilinha estiver desativada.
SushiGuy
1
A resposta de Matt já cobriu isso. I 'Believe' 30 pessoas apenas os olhos vendados up-votado esta resposta :)
123iamking
26

Outra abordagem que usa o LINQ:

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

É muito mais simples do que tudo isso:

while(str.Contains("  ")) str = str.Replace("  ", " ");
Joel Coehoorn
fonte
23
Isso será muito menos eficiente que o regex "{2,}" se a sequência contiver seqüências de 3 ou mais espaços.
Jan Goyvaerts
2
@ JanGoyvaerts: Mesmo com 10 espaços, o regex era mais lento quando eu fiz um teste rápido e sujo. Dito isto, são necessárias apenas uma subcadeia gigante cheia de espaços para eliminar completamente o desempenho do loop while. Para ser justo, usei o RegexOptions.Compiled, em vez do Regex.Replace mais lento.
22713 Brian
5
RegexOptions.Compiled adiciona muita sobrecarga compilando o regex em IL. Não o use, a menos que seu aplicativo use a regex com frequência suficiente ou em cadeias grandes o suficiente para que a maior velocidade de correspondência compense a menor velocidade de compilação.
Jan Goyvaerts
Este é um exemplo de código extremamente ineficiente. RI MUITO.
pcbabu 19/02
1
@pcbabu Não é tão ruim quanto parece para muitos casos. O Replace()método manipula todas as ocorrências de dois espaços em uma determinada sequência, portanto, não estamos fazendo loop (e alocando uma sequência inteira) para todas as instâncias de espaços emparelhados na sequência. Uma nova alocação tratará de todos eles. Só executamos novamente o loop quando havia 3 ou mais espaços juntos, o que provavelmente será uma ocorrência mais rara para muitas fontes de entrada. Se você puder mostrar que isso se torna um problema para seus dados, escreva a máquina de estado para inserir caracteres por caractere em um novo construtor de strings.
Joel Coehoorn
21

Regex pode ser bastante lento, mesmo com tarefas simples. Isso cria um método de extensão que pode ser usado em qualquer um 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();
        }
    }

Seria usado como tal:

string testValue = "This contains     too          much  whitespace."
testValue = testValue.ReduceWhitespace();
// testValue = "This contains too much whitespace."
ScubaSteve
fonte
15
myString = Regex.Replace(myString, " {2,}", " ");
Jan Goyvaerts
fonte
11

Para quem não gosta Regex, aqui está um método que usa 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();
    }

Nos meus testes, esse método era 16 vezes mais rápido, em média, com um conjunto muito grande de cadeias de tamanho pequeno a médio, em comparação com um Regex compilado estático. Comparado a um Regex não compilado ou não estático, isso deve ser ainda mais rápido.

Lembre-se de que ele não remove espaços à esquerda ou à direita, apenas várias ocorrências desse tipo.

Nolonar
fonte
Se você quiser verificar se o personagem é um espaço em branco, e não apenas um espaço, veja minha resposta abaixo .
Reap
8

Você pode simplesmente fazer isso em uma solução de linha!

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

Você pode escolher outros colchetes (ou até outros caracteres), se quiser.

ravish.hacker
fonte
1
Você precisa garantir que sua string não tenha "()" ou ") (" nela. Ou "wel()come to london)("se torna "wel come to london". Você pode tentar usar muitos colchetes. Portanto, use em ((((()))))vez de ()e em )))))(((((vez de )(. Ainda funcionará. Ainda assim, se a string contém ((((()))))ou )))))(((((, isso falhará #
nmit026
7

Esta é uma versão mais curta, que só deve ser usada se você estiver fazendo isso uma vez, pois ela cria uma nova instância da Regexclasse toda vez que é chamada.

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

Se você não conhece muito expressões regulares, aqui está uma breve explicação:

O {2,}torna a pesquisa regex para o personagem que o precede, e encontra substrings entre 2 e ilimitadas vezes.
o.Replace(temp, " ") substitui todas as correspondências na string temp por um espaço.

Se você deseja usar isso várias vezes, aqui está uma opção melhor, pois ela cria a IL do regex em tempo de compilação:

Regex singleSpacify = new Regex(" {2,}", RegexOptions.Compiled);
temp = singleSpacify.Replace(temp, " ");
alguém
fonte
7

no Regex, no Linq ... remove os espaços iniciais e finais, além de reduzir qualquer segmento de espaço múltiplo incorporado em um espaço

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

resultado: "0 1 2 3 4 5"

Stephen du Buis
fonte
1
Uma palavra de cautela: O uso da divisão, embora muito simples de entender, pode ter um impacto surpreendentemente negativo no desempenho. Como muitas seqüências de caracteres podem ser criadas, você precisará observar o uso da memória caso lide com grandes seqüências com esse método.
Pac0
5

Consolando outras respostas, por Joel, e, esperançosamente, melhorando um pouco à medida que vou:

Você pode fazer isso com Regex.Replace():

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

Ou com 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 (" ");
Jay Bazuzi
fonte
3

Acabei de escrever um novo Joinque eu gosto, então pensei em responder novamente:

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

Uma das coisas legais sobre isso é que ele trabalha com coleções que não são strings, chamando ToString () nos elementos. O uso ainda é o mesmo:

//...

string s = "     1  2    4 5".Split (
    " ".ToCharArray(), 
    StringSplitOptions.RemoveEmptyEntries
    ).Join (" ");
Jay Bazuzi
fonte
2
por que criar um método de extensão? por que não usar string.Join ()?
Eric Schoonover
3
      // Mysample string
            string str ="hi you           are          a demo";

            //Split the words based on white sapce
            var demo= str .Split(' ').Where(s => !string.IsNullOrWhiteSpace(s));

            //Join the values back and add a single space in between
                    str = string.Join(" ", demo);

//output: string str ="hi you are a demo";
JIYAUL MUSTAPHA
fonte
2

Eu sei que isso é bem antigo, mas me deparei com isso enquanto tentava realizar quase a mesma coisa. Encontrei esta solução no RegEx Buddy. Esse padrão substitui todos os espaços duplos por espaços simples e também apara os espaços iniciais e finais.

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

É um pouco difícil de ler, já que estamos lidando com espaço vazio, então aqui está novamente com os "espaços" substituídos por um "_".

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

A construção "(? M:" ativa a opção "multi-line". Geralmente, gosto de incluir todas as opções possíveis no próprio padrão, para que fique mais independente.

Paul Easter
fonte
2

Muitas respostas estão fornecendo a saída certa, mas para aqueles que procuram as melhores performances, eu melhorei a resposta de Nolanar (que foi a melhor resposta para o desempenho) em cerca de 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();
    }

}
The_Black_Smurf
fonte
1

Posso remover espaços em branco com este

while word.contains("  ")  //double space
   word = word.Replace("  "," "); //replace double space by single space.
word = word.trim(); //to remove single whitespces from start & end.
Estudante1947
fonte
sim, mas você substituiria apenas dois espaços em branco por um. Isto não ajuda um número X de espaços
MGot90
1
O loop While cuida de todos os espaços duplos a serem removidos.
Learner1947
1

Use o padrão regex

    [ ]+    #only space

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

tente este método

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-o assim:

string test = removeNestedWhitespaces("1 2 3  4    5".toCharArray());
Ahmed Aljaff
fonte
Isso removerá os espaços à direita
The_Black_Smurf 27/02
desculpe pelo erro, i fixa o código, agora é trabalho como corda testado esperado: "1 2 3 4 9" string resultado: "1 2 3 4 9"
Ahmed Aljaff
1

Aqui está uma pequena modificação na resposta original do Nolonar .

Verificando se o caractere não é apenas um espaço, mas qualquer espaço em branco, use o seguinte:

Ele substituirá qualquer caractere de espaço em branco múltiplo por um único espaço.

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

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

Skool antigo:

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 " ) );
um dia quando
fonte
0

Sem usar expressões regulares:

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

OK para usar em cadeias curtas, mas terá um desempenho ruim em cadeias longas com muitos espaços.

Tom Gullen
fonte
0

Mistura de StringBuilder e Enumerable.Aggregate () como método de extensão para seqüências de caracteres:

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   ") + "\"");
    }
}

Entrada:

"1   Hello       World  2   "

Resultado:

"1 Hello World 2 "
Patrick Artner
fonte