Reduzieren Sie Sequenzen von Leerzeichen in ein einzelnes Zeichen und eine Trimmzeichenfolge

122

Betrachten Sie das folgende Beispiel:

"    Hello      this  is a   long       string!   "

Ich möchte das umwandeln in:

"Hello this is a long string!"
hfossli
quelle

Antworten:

125

OS X 10.7+ und iOS 3.2+

Verwenden Sie die native hgexp-Lösung von hfossli.

Andernfalls

Verwenden Sie entweder Ihre bevorzugte reguläre Ausdrucksbibliothek oder die folgende Cocoa-native Lösung:

NSString *theString = @"    Hello      this  is a   long       string!   ";

NSCharacterSet *whitespaces = [NSCharacterSet whitespaceCharacterSet];
NSPredicate *noEmptyStrings = [NSPredicate predicateWithFormat:@"SELF != ''"];

NSArray *parts = [theString componentsSeparatedByCharactersInSet:whitespaces];
NSArray *filteredArray = [parts filteredArrayUsingPredicate:noEmptyStrings];
theString = [filteredArray componentsJoinedByString:@" "];
Georg Schölly
quelle
4
Ich wäre gespannt auf einen Leistungsvergleich mit einem Regex-Ersatz mit einer Verkleidung zum Entfernen der Enden. Einerseits haben Sie einen regulären Ausdruck, mit dem Sie sich befassen müssen. Auf der anderen Seite haben Sie ein Prädikat. Entweder erfordert die interne Verarbeitung der jeweiligen Ausdrücke.
Lilbyrdie
@lilbyrdie: Das hängt von der Zeichenfolge ab, die ich denke, wie viele Leerzeichen es gibt. Meine Lösung ist ziemlich langsam, da sie für jeden Teilstring ein neues Objekt erstellt und Methodenaufrufe an jeden von ihnen sendet.
Georg Schölly
2
Gute Antwort, als solche positiv bewertet, aber ich fordere Ihre Definition von "einfach" heraus. Mit freundlichen Grüßen, ehemaliger Python-Typ jetzt in ObjC-Land ;-)
JK Laiho
2
Sie haben mich zum Lachen gebracht mit "Verwenden Sie keine komplexen Lösungen, wenn es eine einfache gibt". Das einfachste ist also [toBeTrimmed stringByReplacingOccurrencesOfString: @ "" withString: @ ""] nein? Ich stimme Ihrer Antwort immer noch zu, aber es ist definitiv die einfachste
Mário Carvalho
2
@ MárioCarvalho stellt die Frage , wie zu entfernen überschüssige Leerzeichen, nicht alle davon.
Swilliams
52

Regex und NSCharacterSet helfen Ihnen gerne weiter. Diese Lösung schneidet führende und nachfolgende Leerzeichen sowie mehrere Leerzeichen ab.

NSString *original = @"    Hello      this  is a   long       string!   ";

NSString *squashed = [original stringByReplacingOccurrencesOfString:@"[ ]+"
                                                         withString:@" "
                                                            options:NSRegularExpressionSearch
                                                              range:NSMakeRange(0, original.length)];

NSString *final = [squashed stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

Protokollierung finalgibt

"Hello this is a long string!"

Mögliche alternative Regex-Muster:

  • Nur Leerzeichen ersetzen: [ ]+
  • Platz und Tabulatoren ersetzen: [ \\t]+
  • Ersetzen Sie Leerzeichen, Tabulatoren und Zeilenumbrüche: \\s+

Leistungsabfall

Die einfache Erweiterung, Leistung, Anzahl der Codezeilen und die Anzahl der erstellten Objekte machen diese Lösung angemessen.

hfossli
quelle
3
hfossli ist die eleganteste Antwort in meinem Buch. Außerdem habe ich gerade gelernt, dass Sie reguläre Ausdrücke in verwenden können stringByReplacingOccurrencesOfString:. Ich kann nicht glauben, dass ich das nicht wusste.
Davidf2281
1
Genial. Arbeitete wie ein Zauber
Kushal Ashok
41

Eigentlich gibt es dafür eine sehr einfache Lösung:

NSString *string = @" spaces in front and at the end ";
NSString *trimmedString = [string stringByTrimmingCharactersInSet:
                                  [NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(@"%@", trimmedString)

( Quelle )

arikfr
quelle
29
Ich denke, dass dies nur führende und nachfolgende Leerzeichen eliminieren und alle von ihnen eliminieren wird. es wird nicht mit "hallo foo" zu
tun haben
2
d * mn Zeilenenden und automatische Formatierung ... es geht nicht um "hallo______foo" (angenommen _ -> "", weil das Formatieren von Kommentaren schwierig ist)
Brian Postow
32
Warum stimmen Sie ab und antworten, was keine Lösung für die Frage bietet? stringByTrimmingCharactersInSet analysiert nicht die Iside des Strings, sondern nur Kanten. Die Antwort von Georg Sholly ist die perfekte.
Lukasz
3
War nicht gerade eine Antwort auf die Frage, aber es hat mir sicher geholfen. Danke
daveMac
1
Hervorragender Code zum gleichzeitigen Entfernen von führendem und nachfolgendem Leerzeichen.
user523234
13

Mit einem regulären Ausdruck, aber ohne externe Rahmenbedingungen:

NSString *theString = @"    Hello      this  is a   long       string!   ";

theString = [theString stringByReplacingOccurrencesOfString:@" +" withString:@" "
                       options:NSRegularExpressionSearch
                       range:NSMakeRange(0, theString.length)];
MonsieurDart
quelle
Sie müssten dann auch noch das Ergebnis kürzen, sonst werden Sie mit Leerzeichen aufgefüllt. Dies ist jedoch wahrscheinlich die einfachste Antwort.
Lilbyrdie
2
Die Dokumentation für NSRegularExpressionSearchsagt, dass es nur mit den rangeOfString:...Methoden
funktioniert
9

Eine einzeilige Lösung:

NSString *whitespaceString = @" String with whitespaces ";

NSString *trimmedString = [whitespaceString
        stringByReplacingOccurrencesOfString:@" " withString:@""];
TwoBeerGuy
quelle
2
Hat mir geholfen :). Dank dafür!
Freiheit
5
Dies ist zwar nützlich, entfernt jedoch alle Leerzeichen. Das OP möchte im Wesentlichen eine Leerzeichenverdichtung, z. B. ein Trimmen, gefolgt von einer Reduzierung aufeinanderfolgender Leerzeichen auf ein einzelnes Leerzeichen.
Lilbyrdie
Ein weiterer Hinweis: Diese Lösung behandelt keine anderen Tabulatoren, Zeilenumbrüche oder Leerzeichen als Leerzeichen.
Fwielstra
2
Dies beantwortet nicht das OP, sondern entfernt alle Leerzeichen in der Zeichenfolge, so dass Sie am Ende @ "Stringwithwhitespaces"
Charles
6

Das sollte es tun ...

NSString *s = @"this is    a  string    with lots  of     white space";
NSArray *comps = [s componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

NSMutableArray *words = [NSMutableArray array];
for(NSString *comp in comps) {
  if([comp length] > 1)) {
    [words addObject:comp];
  }
}

NSString *result = [words componentsJoinedByString:@" "];
Barry Wark
quelle
1
Funktioniert das tatsächlich mit der Zeichenfolge 'a'? Es ist von Länge 1, soweit ich sehen kann, diese Lösung wird alle geteilten Wörter mit Größe 0 und 1
herausfiltern.
Ja, das ist die Antwort, die ich erwartet hatte. Danke +1
पवन
4

Eine weitere Option für Regex ist RegexKitLite , das sich sehr einfach in ein iPhone-Projekt einbetten lässt:

[theString stringByReplacingOccurencesOfRegex:@" +" withString:@" "];
Daniel Dickison
quelle
3

Versuche dies

NSString *theString = @"    Hello      this  is a   long       string!   ";

while ([theString rangeOfString:@"  "].location != NSNotFound) {
    theString = [theString stringByReplacingOccurrencesOfString:@"  " withString:@" "];
}
sinh99
quelle
3

Hier ist ein Ausschnitt aus einer NSStringErweiterung, in der "self"sich die NSStringInstanz befindet. Es kann verwendet werden zusammenhängende Leerzeichen in ein einzelnes Leerzeichen zu kollabieren , indem in vorbei [NSCharacterSet whitespaceAndNewlineCharacterSet]und ' 'zu den zwei Argumenten.

- (NSString *) stringCollapsingCharacterSet: (NSCharacterSet *) characterSet toCharacter: (unichar) ch {
int fullLength = [self length];
int length = 0;
unichar *newString = malloc(sizeof(unichar) * (fullLength + 1));

BOOL isInCharset = NO;
for (int i = 0; i < fullLength; i++) {
    unichar thisChar = [self characterAtIndex: i];

    if ([characterSet characterIsMember: thisChar]) {
        isInCharset = YES;
    }
    else {
        if (isInCharset) {
            newString[length++] = ch;
        }

        newString[length++] = thisChar;
        isInCharset = NO;
    }
}

newString[length] = '\0';

NSString *result = [NSString stringWithCharacters: newString length: length];

free(newString);

return result;
}
dmercredi
quelle
-1

Alternative Lösung: Besorgen Sie sich eine Kopie von OgreKit (der Cocoa-Bibliothek für reguläre Ausdrücke).

  • OgreKit (japanische Webseite - Code ist in Englisch)
  • OgreKit (Google Autotranslation):

Die ganze Funktion ist dann:

NSString *theStringTrimmed =
   [theString stringByTrimmingCharactersInSet:
        [NSCharacterSet whitespaceAndNewlineCharacterSet]];
OGRegularExpression  *regex =
    [OGRegularExpression regularExpressionWithString:@"\s+"];
return [regex replaceAllMatchesInString:theStringTrimmed withString:@" "]);

Kurz und bündig.

Wenn Sie nach der schnellsten Lösung suchen, NSScannerfunktioniert eine sorgfältig erstellte Reihe von Anweisungen wahrscheinlich am besten. Dies ist jedoch nur erforderlich, wenn Sie große Textblöcke (viele Megabyte) verarbeiten möchten.

Matt Gallagher
quelle
Gibt es einen Grund, OgreKit anstelle von RegExKitLite zu verwenden? regexkit.sourceforge.net Es hat einen sehr ähnlichen replaceOccurrencesOfRegex-Aufruf und funktioniert zusätzlich zu den vorhandenen RegEX-Bibliotheken (nicht sicher, ob Ogre eine ganze RegEX-Engine ist oder was)
Kendall Helmstetter Gelner
Ich bin sicher, dass beide funktionieren werden. Ich habe kein Regexkit verwendet, aber es ist ein guter Vorschlag. Benutzer sollten basierend auf den zugrunde liegenden Bibliotheken auswählen: dem PERL-kompatiblen PCRE (RegExKitLite) und dem Ruby-kompatiblen Oniguruma (OgreKit).
Matt Gallagher
-1

Laut @Mathieu ist Godart die beste Antwort, aber es fehlt eine Zeile. Alle Antworten reduzieren nur den Abstand zwischen den Wörtern. Wenn jedoch Tabulatoren oder Tabulatoren vorhanden sind, lautet dies wie folgt: "Dies ist Text \ t und \ tTab zwischen, so weiter "In dreizeiligem Code werden wir: Die Zeichenfolge, die wir möchten, reduziert Leerzeichen

NSString * str_aLine = @"    this is text \t , and\tTab between      , so on    ";
// replace tabs to space
str_aLine = [str_aLine stringByReplacingOccurrencesOfString:@"\t" withString:@" "];
// reduce spaces to one space
str_aLine = [str_aLine stringByReplacingOccurrencesOfString:@" +" withString:@" "
                                                    options:NSRegularExpressionSearch
                                                      range:NSMakeRange(0, str_aLine.length)];
// trim begin and end from white spaces
str_aLine = [str_aLine stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

Das Ergebnis ist

"this is text , and Tab between , so on"

Ohne Tab zu ersetzen, lautet das Ergebnis:

"this is text    , and  Tab between , so on"
Kosar
quelle
-1

Sie können auch ein einfaches while-Argument verwenden. Es gibt dort keine RegEx-Magie, daher ist es möglicherweise einfacher, sie in Zukunft zu verstehen und zu ändern:

while([yourNSStringObject replaceOccurrencesOfString:@"  "
                         withString:@" "
                         options:0
                         range:NSMakeRange(0, [yourNSStringObject length])] > 0);
Sven-Steffen Arndt
quelle
1
Beantwortet die Frage nicht :) Es werden keine führenden und nachfolgenden Leerzeichen entfernt.
Hfossli
-1

Das Befolgen von zwei regulären Ausdrücken würde je nach den Anforderungen funktionieren

  1. @ "+" für übereinstimmende Leerzeichen und Tabulatoren
  2. @ "\\ s {2,}" zum Abgleichen von Leerzeichen, Tabulatoren und Zeilenumbrüchen

Wenden Sie dann die Instanzmethode von nsstring an stringByReplacingOccurrencesOfString:withString:options:range: an, um sie durch einen einzelnen Leerraum zu ersetzen.

z.B

[string stringByReplacingOccurrencesOfString:regex withString:@" " options:NSRegularExpressionSearch range:NSMakeRange(0, [string length])];

Hinweis: Ich habe die 'RegexKitLite'-Bibliothek für die oben genannten Funktionen für iOS 5.x und höher nicht verwendet.

Apalvai
quelle
Diese Lösung entfernt keine führenden und nachfolgenden Leerzeichen, wie vom OP verlangt.
Hfossli
@hfossli führende / nachfolgende Leerzeichen können entfernt werden, indem direkt die stringByTrimmingCharactersInSet: -Methode von NSString mit dem Zeichensatz new / white line aufgerufen wird. Die obige Lösung bestand darin, die redundanten Räume unabhängig von ihrem Standort zu entfernen.
Apalvai