Wie ersetze ich mehrere Leerzeichen durch ein einzelnes Leerzeichen in C #?


439

Wie kann ich mehrere Leerzeichen in einer Zeichenfolge durch nur ein Leerzeichen in C # ersetzen?

Beispiel:

1 2 3  4    5

wäre:

1 2 3 4 5

1
Eine Zustandsmaschine kann es leicht tun, aber es ist wahrscheinlich übertrieben, wenn Sie es nur brauchen, um Leerzeichen zu entfernen
Adrian

Ich habe in einer doppelten Frage einen Benchmark für die verschiedenen Möglichkeiten hinzugefügt . Stackoverflow.com/a/37592018/582061 . Regex war nicht der schnellste Weg, dies zu tun.
Stian Standahl

Antworten:


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

2
Ich habe das kopiert und eingefügt und es funktioniert. Ich mag REgex wirklich nicht, aber diesmal rettet es mein Leben.
Pokus

9
@Craig ein Kommentar würde ausreichen, IMO. // Dieser Block ersetzt mehrere Leerzeichen durch ein ... :)
Paulwhit

6
Wirklich, RegEx ist dafür übertrieben.
Joel Coehoorn

11
@ Joel: Kann nicht zustimmen. Ich bin mir tatsächlich sicher, dass dieser Weg für ausreichend große Zeichenfolgen effizienter ist als der Ihre und in einer einzigen Zeile ausgeführt werden kann. Wo ist der Overkill?
Konrad Rudolph

24
@ Oscar Joels Code ist keine einfache Schleife durch alle Zeichen! Es ist eine versteckte verschachtelte Schleife mit einem quadratischen Worst-Case. Im Gegensatz dazu ist dieser reguläre Ausdruck linear, baut nur eine einzige Zeichenfolge auf (= drastisch reduzierte Zuordnungskosten im Vergleich zu Joels Code) und außerdem kann die Engine die Hölle daraus optimieren (um ehrlich zu sein, ich bezweifle, dass dies der .NET-Regex ist klug genug dafür, aber theoretisch kann dieser reguläre Ausdruck so billig implementiert werden, dass er nicht einmal mehr lustig ist (er benötigt nur einen DFA mit drei Zuständen, jeweils einem Übergang und keinen zusätzlichen Informationen).
Konrad Rudolph

623

Ich benutze gerne:

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

Da es Läufe von Leerzeichen aller Art (z. B. Tabulatoren, Zeilenumbrüche usw.) abfängt und durch ein einzelnes Leerzeichen ersetzt.


43
Leichte Änderung: Regex.Replace (Quelle, @ "(\ s) \ s +", "$ 1"); Dies gibt den ersten gefundenen Leerzeichen-Typ zurück. Wenn Sie also 5 Registerkarten haben, wird eine Registerkarte zurückgegeben. Falls jemand dies bevorzugt.
FB zehn Kate

@radistao Ihr Link ist für das Ersetzen von Javascript-Zeichenfolgen, nicht für C #.
Shiva

1
@Shiva, / \ s \ s + / ist eine Standard-POSIX-Regex-Anweisung und kann in jeder Sprache mit eigener Syntax konvertiert / verwendet werden
radistao

4
Im Sinne der Lösung von @ FBtenKate: Regex.Replace (Quelle, @ "(\ s) \ 1+", "$ 1"); ersetzt mehrere identische aufeinanderfolgende Zeichen durch ein einzelnes.
François Beaune

1
Um führende und nachfolgende Leerzeichen zu entfernen, sollten Sie die Funktion Trim () mit dieser Funktion verwenden, z. B. 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
Dies ist besser lesbar als Regex, ich bevorzuge es mehr, weil ich keine andere Syntax lernen muss
Michael Bahig

9
Ich mag es, weil es Regex nicht braucht
AleX_

3
Dies wäre für große Saiten ineffizient.
DarcyThomas

3
Dadurch werden auch führende und nachfolgende Leerzeichen entfernt.
Matzi

1
Ich bevorzuge auch diese Antwort. Mein alter Mentor pflegte zu sagen: "Immer wenn Sie ein Problem haben, von dem Sie glauben, dass Sie Regex brauchen, um es zu lösen, nun ... jetzt haben Sie ZWEI Probleme" <wink>
William Madonna Jr.

38

Ich denke, Matts Antwort ist die beste, aber ich glaube nicht, dass es ganz richtig ist. Wenn Sie Zeilenumbrüche ersetzen möchten, müssen Sie Folgendes verwenden:

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

4
RegexOptions.Multiline ändert die Bedeutung von ^ und $ so, dass sie mit dem Anfang und Ende jeder Zeile ($ = \ n) anstelle der gesamten mehrzeiligen Zeichenfolge übereinstimmen. Da \ s [\ f \ n \ r \ t \ v] entspricht, sollten die Zeilenumbrüche ersetzt werden, auch wenn die Option Mehrzeilig deaktiviert ist.
SushiGuy

1
Matts Antwort hat dies bereits behandelt. Ich 'glaube', dass 30 Personen diese Antwort nur mit verbundenen Augen
hochgestimmt

26

Ein weiterer Ansatz, der LINQ verwendet:

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

23

Es ist viel einfacher als das alles:

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

23
Dies ist weitaus weniger effizient als der reguläre Ausdruck "{2,}", wenn die Zeichenfolge Sequenzen mit 3 oder mehr Leerzeichen enthält.
Jan Goyvaerts

2
@ JanGoyvaerts: Selbst mit 10 Leerzeichen war die Regex langsamer, als ich einen schnellen und schmutzigen Test machte. Davon abgesehen ist nur ein riesiger Teilstring voller Leerzeichen erforderlich, um die Leistung der while-Schleife vollständig zu beenden. Aus Fairnessgründen habe ich RegexOptions.Compiled anstelle des langsameren Regex.Replace verwendet.
Brian

5
RegexOptions.Compiled fügt viel Aufwand hinzu, um den Regex in IL zu kompilieren. Verwenden Sie es nur, wenn Ihre Anwendung den regulären Ausdruck häufig genug oder auf ausreichend großen Zeichenfolgen verwendet, damit die erhöhte Übereinstimmungsgeschwindigkeit die verringerte Kompilierungsgeschwindigkeit ausgleicht.
Jan Goyvaerts

Dies ist ein Beispiel für extrem ineffizienten Code. LOL.
pcbabu

1
@pcbabu Es ist nicht so schlimm, wie es in vielen Fällen scheint. Die Replace()Methode behandelt alle Vorkommen von zwei Leerzeichen in einer bestimmten Zeichenfolge, sodass wir nicht für jede Instanz gepaarter Leerzeichen in der Zeichenfolge eine Schleife erstellen (und eine ganze Zeichenfolge neu zuweisen). Eine neue Zuordnung behandelt alle. Wir führen die Schleife nur dann erneut aus, wenn 3 oder mehr Leerzeichen zusammen vorhanden sind, was bei vielen Eingabequellen wahrscheinlich seltener vorkommt. Wenn Sie zeigen können, dass es ein Problem für Ihre Daten wird, schreiben Sie die Zustandsmaschine, um Zeichen für Zeichen in einen neuen Stringbuilder zu verschieben.
Joel Coehoorn

21

Regex kann selbst bei einfachen Aufgaben ziemlich langsam sein. Dadurch wird eine Erweiterungsmethode erstellt, die von jedem verwendet werden kann 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();
        }
    }

Es würde als solches verwendet werden:

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


11

Für diejenigen, die nicht mögen Regex, ist hier eine Methode, die verwendet 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 meinen Tests war diese Methode mit einem sehr großen Satz kleiner bis mittlerer Zeichenfolgen im Durchschnitt 16-mal schneller als mit einem statisch kompilierten Regex. Im Vergleich zu einem nicht kompilierten oder nicht statischen Regex sollte dies noch schneller sein.

Beachten Sie, dass führende oder nachfolgende Leerzeichen nicht entfernt werden , sondern nur das mehrfache Auftreten solcher Leerzeichen.


Wenn Sie überprüfen möchten, ob das Zeichen ein Leerzeichen und nicht nur ein Leerzeichen ist, lesen Sie meine Antwort unten .
Ernte

8

Sie können dies einfach in einer einzeiligen Lösung tun!

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

Sie können andere Klammern (oder sogar andere Zeichen) auswählen, wenn Sie möchten.


1
Sie müssen sicherstellen, dass Ihre Zeichenfolge nicht "()" oder ") (" enthält. Oder "wel()come to london)("wird "wel come to london". Sie könnten versuchen, viele Klammern zu verwenden. Verwenden Sie also ((((()))))anstelle von ()und )))))(((((anstelle von )(. Es wird immer noch funktionieren. Trotzdem, wenn Die Zeichenfolge enthält ((((()))))oder )))))(((((, dies wird fehlschlagen.
nmit026

7

Dies ist eine kürzere Version, die nur verwendet werden sollte, wenn Sie dies nur einmal tun, da bei Regexjedem Aufruf eine neue Instanz der Klasse erstellt wird.

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

Wenn Sie mit regulären Ausdrücken nicht allzu vertraut sind, finden Sie hier eine kurze Erklärung:

Der {2,}Regex sucht nach dem Zeichen davor und findet Teilzeichenfolgen zwischen 2 und unbegrenzt oft.
Das .Replace(temp, " ")ersetzt alle Übereinstimmungen in der Zeichenfolgentemp durch ein Leerzeichen.

Wenn Sie dies mehrmals verwenden möchten, ist hier eine bessere Option, da die Regex-IL zur Kompilierungszeit erstellt wird:

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

7

no Regex, no Linq ... entfernt führende und nachfolgende Leerzeichen und reduziert alle eingebetteten Mehrfachraumsegmente auf ein Leerzeichen

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

Ergebnis: "0 1 2 3 4 5"


1
Ein Wort der Vorsicht: Die Verwendung von Split ist zwar sehr einfach zu verstehen, kann jedoch überraschend negative Auswirkungen auf die Leistung haben. Da viele Zeichenfolgen erstellt werden können, müssen Sie Ihre Speichernutzung überwachen, wenn Sie mit dieser Methode große Zeichenfolgen verarbeiten.
Pac0

5

Andere Antworten trösten, per Joel, und hoffentlich leicht verbessern, wenn ich gehe:

Sie können dies tun mit Regex.Replace():

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

Oder mit 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

Ich habe gerade eine neue geschrieben Join, die mir gefällt, also dachte ich, ich würde damit antworten:

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

Eines der coolen Dinge dabei ist, dass es mit Sammlungen funktioniert, die keine Zeichenfolgen sind, indem ToString () für die Elemente aufgerufen wird. Die Verwendung ist immer noch die gleiche:

//...

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

2
Warum eine Erweiterungsmethode erstellen? Warum nicht einfach string.Join () verwenden?
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

Ich weiß, dass dies ziemlich alt ist, bin aber darauf gestoßen, als ich versucht habe, fast das Gleiche zu erreichen. Diese Lösung wurde in RegEx Buddy gefunden. Dieses Muster ersetzt alle doppelten Leerzeichen durch einzelne Leerzeichen und schneidet auch führende und nachfolgende Leerzeichen.

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

Es ist ein wenig schwer zu lesen, da es sich um einen leeren Raum handelt. Hier werden also wieder die "Räume" durch ein "_" ersetzt.

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

Das Konstrukt "(? M:" aktiviert die Option "mehrzeilig". Im Allgemeinen möchte ich alle möglichen Optionen in das Muster selbst aufnehmen, damit es eigenständiger ist.


2

Viele Antworten liefern die richtige Ausgabe, aber für diejenigen, die nach den besten Leistungen suchen, habe ich Nolanars Antwort (die die beste Antwort für die Leistung war) um etwa 10% verbessert .

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

Ich kann damit Leerzeichen entfernen

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

Ja, aber Sie würden nur zwei Leerzeichen durch eines ersetzen. Dies würde X Anzahl der Leerzeichen nicht helfen
MGot90

1
Diese While-Schleife kümmert sich um alle zu entfernenden doppelten Leerzeichen.
Learner1947

1

Verwenden Sie das Regex-Muster

    [ ]+    #only space

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

1

Versuchen Sie diese Methode

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

benutze es so:

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

Dies wird die nachgestellten Leerzeichen entfernen
The_Black_Smurf

Entschuldigung für den Fehler, ich habe den Code behoben, jetzt funktioniert es wie erwartet getestet Zeichenfolge: "1 2 3 4 9" Ergebniszeichenfolge: "1 2 3 4 9"
Ahmed Aljaff

1

Hier ist eine geringfügige Änderung der ursprünglichen Antwort von Nolonar .

Überprüfen Sie Folgendes, um zu überprüfen, ob das Zeichen nicht nur ein Leerzeichen, sondern ein Leerzeichen ist:

Es werden mehrere Leerzeichen durch ein einzelnes Leerzeichen ersetzt.

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

Alte Schule:

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

Ohne reguläre Ausdrücke zu verwenden:

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

OK für kurze Saiten, aber für lange Saiten mit viel Leerzeichen schlecht.


0

Mix aus StringBuilder und Enumerable.Aggregate () als Erweiterungsmethode für 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   ") + "\"");
    }
}

Eingang:

"1   Hello       World  2   "

Ausgabe:

"1 Hello World 2 "
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.