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
Pokus
quelle
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, " ");
Patrick Desjardins
quelle
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.

Matt
quelle
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 ));
Tvanfosson
quelle
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);
Brenda Bell
quelle
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);
cuongle
quelle
23

Es ist viel einfacher als das alles:

while(str.Contains("  ")) str = str.Replace("  ", " ");
Joel Coehoorn
quelle
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."
ScubaSteve
quelle
15
myString = Regex.Replace(myString, " {2,}", " ");
Jan Goyvaerts
quelle
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.

Nolonar
quelle
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.

ravish.hacker
quelle
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, " ");
jemand
quelle
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"

Stephen du Buis
quelle
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 (" ");
Jay Bazuzi
quelle
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 (" ");
Jay Bazuzi
quelle
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";
JIYAUL MUSTAPHA
quelle
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.

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

}
The_Black_Smurf
quelle
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.
Learner1947
quelle
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, @"[ ]+", " ");
M. Hassan
quelle
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());
Ahmed Aljaff
quelle
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();
}
Ernten
quelle
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 " ) );
eines Tages, wenn
quelle
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.

Tom Gullen
quelle
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 "
Patrick Artner
quelle