Comment remplacer plusieurs espaces par un seul espace en C #?


440

Comment remplacer plusieurs espaces dans une chaîne par un seul espace en C #?

Exemple:

1 2 3  4    5

serait:

1 2 3 4 5

1
une machine d'état peut facilement le faire, mais c'est probablement exagéré si vous n'en avez besoin que pour supprimer des espaces
Adrian

J'ai ajouté un point de repère sur les différentes façons de le faire dans une question en double stackoverflow.com/a/37592018/582061 . Regex n'était pas le moyen le plus rapide de le faire.
Stian Standahl

Réponses:


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
J'ai copié et collé ça et ça marche. Je n'aime vraiment pas REgex mais cette fois cela me sauve la vie.
Pokus

9
@Craig un commentaire suffirait, OMI. // Ce bloc remplace plusieurs espaces par un ... :)
paulwhit

6
Vraiment, RegEx est exagéré pour cela.
Joel Coehoorn

11
@Joel: Je ne peux pas être d'accord. Je suis en fait sûr que cette méthode est plus efficace que la vôtre pour des chaînes suffisamment grandes et peut être effectuée sur une seule ligne. Où est l'excès?
Konrad Rudolph

24
Le code de @Oscar Joel n'est pas une simple boucle à travers tous les caractères! C'est une boucle imbriquée cachée qui présente le pire cas quadratique. Cette expression régulière, en revanche, est linéaire, ne construit qu'une seule chaîne (= coûts d'allocation considérablement réduits par rapport au code de Joel) et en outre le moteur peut optimiser l'enfer (pour être honnête, je doute que l'expression régulière .NET soit assez intelligent pour cela, mais en théorie, cette expression régulière peut être implémentée à un prix si bas qu'elle n'est même plus drôle; elle n'a besoin que d'un DFA avec trois états, une transition chacun et aucune information supplémentaire).
Konrad Rudolph

624

J'aime utiliser:

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

Puisqu'il attrapera des courses de n'importe quel genre d'espace blanc (par exemple des tabulations, des nouvelles lignes, etc.) et les remplacera par un espace simple.


43
Légère modification: Regex.Replace (source, @ "(\ s) \ s +", "$ 1"); Cela renverra le premier type d'espace blanc trouvé. Donc, si vous avez 5 onglets, il renverra un onglet. Au cas où quelqu'un préfère cela.
FB ten Kate

@radistao Votre lien est pour remplacer la chaîne Javascript, pas pour C #.
Shiva

1
@Shiva, / \ s \ s + / est une instruction regex POSIX standard et peut être convertie / utilisée dans n'importe quelle langue en utilisant sa propre syntaxe
radistao

4
Dans l'esprit de la solution de @ FBtenKate: Regex.Replace (source, @ "(\ s) \ 1+", "$ 1"); remplacera plusieurs caractères consécutifs identiques par un seul.
François Beaune

1
afin de supprimer les espaces blancs de début et de fin, vous devez utiliser la fonction Trim () avec ceci ,, comme 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
C'est plus lisible que regex, je le préfère plus parce que je n'ai pas besoin d'apprendre une autre syntaxe
Michael Bahig

9
Je l'aime parce qu'il n'a pas besoin de Regex
AleX_

3
Ce serait inefficace pour les grandes chaînes.
DarcyThomas

3
Cela supprime également les espaces de début et de fin.
Matzi

1
Je préfère également cette réponse. Mon ancien mentor disait «chaque fois que vous avez un problème, vous pensez que vous avez besoin de Regex pour le résoudre, eh bien ... maintenant vous avez DEUX problèmes" <clin d'œil>
William Madonna Jr.

38

Je pense que la réponse de Matt est la meilleure, mais je ne pense pas que ce soit tout à fait juste. Si vous souhaitez remplacer les sauts de ligne, vous devez utiliser:

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

4
RegexOptions.Multiline change la signification de ^ et $ afin qu'ils correspondent au début et à la fin de chaque ligne ($ = \ n), au lieu de la chaîne multi-lignes entière. Parce que \ s est équivalent à [\ f \ n \ r \ t \ v], les sauts de ligne doivent être remplacés même si l'option Multiligne est désactivée.
SushiGuy

1
La réponse de Matt a déjà couvert cela. Je 'crois' que 30 personnes ont simplement voté les yeux bandés pour cette réponse :)
123iamking

26

Une autre approche qui utilise LINQ:

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

23

C'est beaucoup plus simple que ça:

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

23
Ce sera beaucoup moins efficace que l'expression régulière "{2,}" si la chaîne contient des séquences de 3 espaces ou plus.
Jan Goyvaerts

2
@JanGoyvaerts: Même avec 10 espaces, l'expression régulière était plus lente lorsque j'ai fait un test rapide et sale. Cela étant dit, il suffit d'une seule sous-chaîne géante pleine d'espaces pour tuer complètement les performances de la boucle while. Par souci d'équité, j'ai utilisé J'ai utilisé RegexOptions.Compiled, plutôt que le Regex.Replace plus lent.
Brian

5
RegexOptions.Compiled ajoute beaucoup de frais généraux lors de la compilation de l'expression régulière en IL. Ne l'utilisez pas sauf si votre application utilisera l'expression régulière assez souvent ou sur des chaînes suffisamment grandes pour que la vitesse de correspondance accrue compense la vitesse de compilation réduite.
Jan Goyvaerts

Ceci est un exemple de code extrêmement inefficace. LOL.
pcbabu

1
@pcbabu Ce n'est pas aussi mauvais qu'il n'y paraît dans de nombreux cas. La Replace()méthode gérera toutes les occurrences de deux espaces dans une chaîne donnée, donc nous ne bouclons pas (et ne réallouons pas une chaîne entière) pour chaque instance d'espaces appariés dans la chaîne. Une nouvelle allocation les gérera tous. Nous ne réexécutons la boucle que lorsqu'il y avait 3 espaces ou plus ensemble, ce qui est probablement plus rare pour de nombreuses sources d'entrée. Si vous pouvez montrer que cela devient un problème pour vos données, alors écrivez la machine d'état pour pousser caractère par caractère dans un nouveau constructeur de chaînes.
Joel Coehoorn

21

Regex peut être assez lent, même avec des tâches simples. Cela crée une méthode d'extension qui peut être utilisée à partir de n'importe quel 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();
        }
    }

Il serait utilisé comme tel:

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


11

Pour ceux qui n'aiment pas Regex, voici une méthode qui utilise 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();
    }

Dans mes tests, cette méthode était en moyenne 16 fois plus rapide avec un très grand ensemble de chaînes de petite à moyenne taille, par rapport à une Regex compilée statique. Comparé à une regex non compilée ou non statique, cela devrait être encore plus rapide.

Gardez à l'esprit qu'il ne supprime pas les espaces de début ou de fin, mais uniquement les occurrences multiples de ceux-ci.


Si vous voulez vérifier si le caractère est un espace, et pas seulement un espace, voyez ma réponse ci-dessous .
Reap

8

Vous pouvez simplement le faire en une seule solution!

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

Vous pouvez choisir d'autres parenthèses (ou même d'autres caractères) si vous le souhaitez.


1
Vous devez vous assurer que votre chaîne ne contient pas "()" ou ") (". Ou "wel()come to london)("devient "wel come to london". Vous pouvez essayer d'utiliser beaucoup de crochets. Utilisez donc à la ((((()))))place de ()et à la )))))(((((place de )(. Cela fonctionnera toujours. la chaîne contient ((((()))))ou )))))(((((, cela échouera.
nmit026

7

Il s'agit d'une version plus courte, qui ne doit être utilisée que si vous ne le faites qu'une seule fois, car elle crée une nouvelle instance de la Regex classe à chaque appel.

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

Si vous n'êtes pas trop familier avec les expressions régulières, voici une courte explication:

le {2,} fait que l'expression régulière recherche le caractère qui le précède et trouve des sous-chaînes entre 2 et un nombre illimité de fois.
Le .Replace(temp, " ")remplace toutes les correspondances dans la chaîne de caractères par un espace.

Si vous souhaitez l'utiliser plusieurs fois, voici une meilleure option, car elle crée l'IL regex au moment de la compilation:

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

7

pas de Regex, pas de Linq ... supprime les espaces de début et de fin ainsi que la réduction de tous les segments d'espace intégrés dans un seul espace

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

résultat: "0 1 2 3 4 5"


1
Un mot d'avertissement: L'utilisation de la division, bien que très simple à comprendre, peut avoir un impact sur les performances étonnamment négatif. Comme de nombreuses chaînes peuvent être créées, vous devrez surveiller votre utilisation de la mémoire au cas où vous manipuleriez de grandes chaînes avec cette méthode.
Pac0

5

Consolider d'autres réponses, par Joel, et, espérons-le, s'améliorer légèrement au fur et à mesure:

Vous pouvez le faire avec Regex.Replace():

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

Ou avec 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

Je viens d'écrire une nouvelle Joinque j'aime, alors j'ai pensé que je répondrais de nouveau avec:

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

Une des choses intéressantes à ce sujet est qu'il fonctionne avec des collections qui ne sont pas des chaînes, en appelant ToString () sur les éléments. L'utilisation est toujours la même:

//...

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

2
pourquoi créer une méthode d'extension? pourquoi ne pas simplement utiliser 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

Je sais que c'est assez vieux, mais je l'ai rencontré en essayant d'accomplir presque la même chose. Trouvé cette solution dans RegEx Buddy. Ce modèle remplacera tous les espaces doubles par des espaces simples et coupera également les espaces de début et de fin.

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

C'est un peu difficile à lire car nous avons affaire à un espace vide, donc ici, c'est à nouveau avec les "espaces" remplacés par un "_".

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

La construction "(? M:" active l'option "multiligne". J'aime généralement inclure toutes les options que je peux dans le motif lui-même afin qu'il soit plus autonome.


2

De nombreuses réponses fournissent la bonne sortie, mais pour ceux qui recherchent les meilleures performances, j'ai amélioré la réponse de Nolanar (qui était la meilleure réponse pour les performances) d'environ 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

Je peux supprimer les espaces blancs avec ceci

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

oui mais vous ne remplaceriez que deux espaces blancs par un. Cela n'aiderait pas le nombre X d'espaces
MGot90

1
Cette boucle While prendra en charge tous les espaces doubles à supprimer.
Learner1947

1

Utilisez le modèle regex

    [ ]+    #only space

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

1

essayez cette méthode

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

utilisez-le comme ceci:

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

Cela supprimera les espaces de fin
The_Black_Smurf

désolé pour l'erreur, j'ai corrigé le code, maintenant il fonctionne comme prévu chaîne testée: "1 2 3 4 9" chaîne de résultat: "1 2 3 4 9"
Ahmed Aljaff

1

Voici une légère modification de la réponse originale de Nolonar .

Pour vérifier si le caractère n'est pas seulement un espace, mais n'importe quel espace, utilisez ceci:

Il remplacera tout caractère d'espaces multiples par un seul espace.

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

Vieille école:

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

Sans utiliser d'expressions régulières:

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

OK à utiliser sur les chaînes courtes, mais fonctionne mal sur les chaînes longues avec beaucoup d'espace.


0

Mélange de StringBuilder et Enumerable.Aggregate () comme méthode d'extension pour les chaînes:

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

Contribution:

"1   Hello       World  2   "

Production:

"1 Hello World 2 "
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.