Come posso sostituire più spazi con un singolo spazio in C #?


440

Come posso sostituire più spazi in una stringa con un solo spazio in C #?

Esempio:

1 2 3  4    5

sarebbe:

1 2 3 4 5

1
una macchina statale può facilmente farlo, ma probabilmente è eccessivo se ne hai bisogno solo per rimuovere gli spazi
Adrian

Ho aggiunto un benchmark sui diversi modi per farlo in una domanda duplicata stackoverflow.com/a/37592018/582061 . Regex non è stato il modo più veloce per farlo.
Stian Standahl,

Risposte:


469
string sentence = "This is a sentence with multiple    spaces";
RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);     
sentence = regex.Replace(sentence, " ");

2
Ho copia e incolla quello e funziona. REgex non mi piace davvero, ma questa volta mi salva la vita.
Pokus,

9
@Craig basterebbe un commento, IMO. // Questo blocco sostituisce più spazi con uno ... :)
paulwhit,

6
Davvero, RegEx è eccessivo per questo.
Joel Coehoorn,

11
@Joel: non posso essere d'accordo. In realtà sono sicuro che in questo modo è più efficiente del tuo per stringhe abbastanza grandi e può essere fatto in una sola riga. Dov'è l'eccesso?
Konrad Rudolph,

24
@Oscar Il codice di Joel non è un semplice ciclo attraverso tutti i personaggi! È un ciclo annidato nascosto che presenta un caso peggiore quadratico. Questa espressione regolare, al contrario, è lineare, costruisce solo una singola stringa (= costi di allocazione drasticamente ridotti rispetto al codice di Joel) e inoltre il motore può ottimizzarne l'inferno (a dire il vero, dubito che la regex di .NET sia abbastanza intelligente per questo, ma in teoria questa espressione regolare può essere implementata in modo così economico che non è nemmeno più divertente; ha solo bisogno di un DFA con tre stati, una transizione ciascuno e nessuna informazione aggiuntiva).
Konrad Rudolph

624

Mi piace usare:

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

Dal momento che catturerà corse di qualsiasi tipo di spazio bianco (ad esempio schede, nuove righe, ecc.) E le sostituirà con un singolo spazio.


43
Leggera modifica: Regex.Replace (source, @ "(\ s) \ s +", "$ 1"); Ciò restituirà il primo tipo di spazio bianco trovato. Quindi, se hai 5 schede, verrà restituita una scheda. In caso qualcuno preferisca questo.
FB dieci Kate,

@radistao Il tuo link è per la sostituzione della stringa Javascript, non per C #.
Shiva,

1
@Shiva, / \ s \ s + / è un'istruzione regex POSIX standard e può essere convertita / utilizzata in qualsiasi lingua utilizzando la propria sintassi
radistao,

4
Nello spirito della soluzione di @ FBtenKate: Regex.Replace (source, @ "(\ s) \ 1+", "$ 1"); sostituirà più caratteri consecutivi identici con uno singolo.
François Beaune,

1
per rimuovere gli spazi bianchi iniziali e finali devi usare la funzione Trim () con questa, come var myString = Regex.Replace (myString, @ "\ s +", "") .Trim ();
Harish Nayak,

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

6
Questo è più leggibile rispetto a regex, lo preferisco di più perché non ho bisogno di imparare qualche altra sintassi
Michael Bahig,

9
Mi piace perché non ha bisogno di Regex
AleX_

3
Ciò sarebbe inefficiente per stringhe di grandi dimensioni.
Darcy Thomas

3
Ciò rimuove anche gli spazi iniziali e finali.
Matzi,

1
Preferisco anche questa risposta. Il mio vecchio mentore diceva "ogni volta che hai un problema pensi di aver bisogno di Regex per risolvere, beh ... ora hai DUE problemi" <wink>
William Madonna Jr.

38

Penso che la risposta di Matt sia la migliore, ma non credo sia del tutto giusta. Se si desidera sostituire le nuove righe, è necessario utilizzare:

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

4
RegexOptions.Multiline modifica il significato di ^ e $ in modo che corrispondano all'inizio e alla fine di ogni riga ($ = \ n), anziché all'intera stringa a più righe. Poiché \ s equivale a [\ f \ n \ r \ t \ v] le nuove righe dovrebbero essere sostituite anche se l'opzione Multiline è disattivata.
SushiGuy

1
La risposta di Matt ha già trattato questo. "Credo" che 30 persone
abbiano

26

Un altro approccio che utilizza LINQ:

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

23

È molto più semplice di tutto ciò:

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

23
Questo sarà molto meno efficiente della regex "{2,}" se la stringa contiene sequenze di 3 o più spazi.
Jan Goyvaerts,

2
@JanGoyvaerts: Anche con 10 spazi, la regex era più lenta quando ho fatto un test veloce e sporco. Detto questo, basta una sola sottostringa gigante piena di spazi per uccidere completamente le prestazioni del ciclo while. Per onestà, ho usato RegexOptions.Compiled, piuttosto che il Regex.Replace più lento.
Brian,

5
RegexOptions.Compiled aggiunge un sacco di overhead compilando la regex in IL. Non utilizzarlo a meno che l'applicazione non utilizzi regex abbastanza spesso o su stringhe abbastanza grandi che la maggiore velocità di corrispondenza compensi la ridotta velocità di compilazione.
Jan Goyvaerts,

Questo è un esempio di codice estremamente inefficiente. LOL.
pcbabu,

1
@pcbabu Non è così male come sembra in molti casi. Il Replace()metodo gestirà tutte le occorrenze di due spazi in una determinata stringa, quindi non stiamo eseguendo il loop (e riassegnando un'intera stringa) per ogni istanza di spazi associati nella stringa. Una nuova allocazione li gestirà tutti. Rieseguiamo il loop solo quando c'erano 3 o più spazi insieme, il che è probabilmente un evento più raro per molte fonti di input. Se puoi mostrare che diventa un problema per i tuoi dati, allora vai a scrivere la macchina a stati per inserire carattere per carattere in un nuovo costruttore di stringhe.
Joel Coehoorn,

21

Regex può essere piuttosto lento anche con compiti semplici. Questo crea un metodo di estensione che può essere utilizzato al di fuori di qualsiasi 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();
        }
    }

Sarebbe usato come tale:

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


11

Per coloro a cui non piace Regex, ecco un metodo che utilizza 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();
    }

Nei miei test, questo metodo era in media 16 volte più veloce con un set molto ampio di stringhe di dimensioni medio-piccole, rispetto a un Regex compilato statico. Rispetto a un Regex non compilato o non statico, questo dovrebbe essere ancora più veloce.

Tieni presente che non rimuove gli spazi iniziali o finali, ma solo più occorrenze di tali.


Se vuoi controllare se il personaggio è uno spazio bianco e non solo uno spazio, vedi la mia risposta qui sotto .
Raccogli il

8

Puoi semplicemente farlo in un'unica soluzione!

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

Puoi scegliere altre parentesi (o anche altri caratteri), se lo desideri.


1
Devi assicurarti che la tua stringa non contenga "()" o ") (" in essa. O "wel()come to london)("diventa "wel come to london". Puoi provare a usare molte parentesi. Quindi usa ((((()))))invece di ()e )))))(((((invece di )(. Funzionerà ancora. Comunque, se la stringa contiene ((((()))))o )))))(((((, questo fallirà.
nmit026

7

Questa è una versione più breve, che dovrebbe essere utilizzata solo se lo fai solo una volta, poiché crea una nuova istanza della Regexclasse ogni volta che viene chiamata.

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

Se non conosci troppo le espressioni regolari, ecco una breve spiegazione:

La {2,}rende la ricerca regex per il carattere che lo precede, e trova sottostringhe tra 2 e numero illimitato di volte.
Il .Replace(temp, " ")sostituisce tutte le partite della temperatura stringa con uno spazio.

Se vuoi usarlo più volte, ecco un'opzione migliore, in quanto crea il regex IL al momento della compilazione:

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

7

no Regex, no Linq ... rimuove gli spazi iniziali e finali e riduce qualsiasi segmento di spazio multiplo incorporato in uno spazio

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

risultato: "0 1 2 3 4 5"


1
Un avvertimento: l'uso di split, sebbene molto semplice da capire, può avere un impatto sorprendentemente negativo sulle prestazioni. Poiché è possibile creare molte stringhe, dovrai controllare l'utilizzo della memoria nel caso in cui gestisci stringhe di grandi dimensioni con questo metodo.
Pac0

5

Consolodando altre risposte, secondo Joel, e si spera che migliorino leggermente mentre vado:

Puoi farlo con Regex.Replace():

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

O con 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 (" ");

3

Ho appena scritto un nuovo Joinche mi piace, quindi ho pensato di rispondere di nuovo, con esso:

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

Una delle cose interessanti di questo è che funziona con raccolte che non sono stringhe, chiamando ToString () sugli elementi. L'utilizzo è sempre lo stesso:

//...

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

2
perché creare un metodo di estensione? perché non usare solo 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";

2

So che è piuttosto vecchio, ma mi sono imbattuto in questo mentre cercavo di ottenere quasi la stessa cosa. Ho trovato questa soluzione in RegEx Buddy. Questo modello sostituirà tutti i doppi spazi con spazi singoli e taglierà anche gli spazi iniziali e finali.

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

È un po 'difficile da leggere poiché abbiamo a che fare con uno spazio vuoto, quindi eccolo di nuovo con gli "spazi" sostituiti da uno "_".

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

Il costrutto "(? M:" abilita l'opzione "multi-linea". In genere mi piace includere tutte le opzioni che posso all'interno del modello stesso, in modo che sia più autonomo.


2

Molte risposte stanno fornendo il giusto risultato ma per coloro che sono alla ricerca delle migliori prestazioni, ho migliorato la risposta di Nolanar (che era la migliore risposta per le prestazioni) di circa il 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

Posso rimuovere gli spazi bianchi con questo

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

sì, ma sostituiresti solo due spazi bianchi con uno. Ciò non aiuterebbe X numero di spazi
MGot90

1
Quel ciclo While si occuperà di tutti quei doppi spazi da rimuovere.
Principiante 1947,

1

Usa il modello regex

    [ ]+    #only space

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

1

prova questo metodo

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();
}

usalo così:

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

Questo rimuoverà gli spazi finali
The_Black_Smurf

scusate l'errore, ho corretto il codice, ora funziona come previsto stringa testata: "1 2 3 4 9" stringa risultato: "1 2 3 4 9"
Ahmed Aljaff

1

Ecco una leggera modifica sulla risposta originale di Nolonar .

Verifica se il personaggio non è solo uno spazio, ma uno spazio bianco, usa questo:

Sostituirà qualsiasi carattere a più spazi bianchi con un singolo spazio.

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();
}

0

Vecchia scuola:

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 " ) );

0

Senza usare espressioni regolari:

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

OK da usare su stringhe brevi, ma funzionerà male su stringhe lunghe con molti spazi.


0

Mix di StringBuilder e Enumerable.Aggregate () come metodo di estensione per le stringhe:

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

Ingresso:

"1   Hello       World  2   "

Produzione:

"1 Hello World 2 "
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.