Réduire les séquences d'espaces blancs en un seul caractère et couper la chaîne

122

Prenons l'exemple suivant:

"    Hello      this  is a   long       string!   "

Je veux convertir cela en:

"Hello this is a long string!"
hfossli
la source

Réponses:

125

OS X 10.7+ et iOS 3.2+

Utilisez la solution d'expression régulière native fournie par hfossli.

Autrement

Utilisez votre bibliothèque de regexp préférée ou utilisez la solution native Cocoa suivante:

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
la source
4
Je serais curieux de comparer les performances de cela à un remplacement de regex avec une garniture pour supprimer les extrémités. D'une part, vous avez une regex à gérer. De l'autre, vous avez un prédicat. L'un ou l'autre nécessite un traitement interne des expressions respectives.
lilbyrdie
@lilbyrdie: Cela dépend de la chaîne, je pense, du nombre d'espaces blancs. Ma solution est assez lente, car elle crée un nouvel objet pour chaque sous-chaîne et envoie des appels de méthode à chacune d'elles.
Georg Schölly
2
Bonne réponse, votée comme telle, mais je conteste votre définition de «facile». Sincèrement, ancien gars de Python maintenant à ObjC-land ;-)
JK Laiho
2
Vous m'avez fait rire avec «n'utilisez pas de solutions complexes s'il y en a une facile». Le plus simple est donc [toBeTrimmed stringByReplacingOccurrencesOfString: @ "" withString: @ ""] non? Je vote toujours votre réponse mais c'est certainement la plus simple
Mário Carvalho
2
@ MárioCarvalho La question demande comment supprimer les espaces blancs en excès , pas tous.
swilliams
52

Regex et NSCharacterSet sont là pour vous aider. Cette solution supprime les espaces blancs de début et de fin ainsi que plusieurs espaces.

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]];

La journalisation finaldonne

"Hello this is a long string!"

Modèles de regex alternatifs possibles:

  • Remplacez uniquement l'espace: [ ]+
  • Remplacez l'espace et les onglets: [ \\t]+
  • Remplacez l'espace, les tabulations et les retours à la ligne: \\s+

Aperçu des performances

La facilité d'extension, les performances, le nombre de lignes de code et le nombre d'objets créés rendent cette solution appropriée.

hfossli
la source
3
hfossli est la réponse la plus élégante dans mon livre. De plus, je viens d'apprendre que vous pouvez utiliser des expressions régulières dans stringByReplacingOccurrencesOfString:. Je ne peux pas croire que je ne le savais pas.
davidf2281
1
Impressionnant. A travaillé comme un charme
Kushal Ashok
41

En fait, il existe une solution très simple à cela:

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

( Source )

arikfr
la source
29
Je pense que cela éliminera uniquement les espaces de début et de fin, et les éliminera tous. il ne traitera pas "hello foo"
Brian Postow
2
d * mn fins de ligne et formatage automatique ... il ne traite pas de "hello______foo" (supposons que _ -> "" car le formatage des commentaires est difficile)
Brian Postow
32
Pourquoi votez-vous et répondez-vous qui n'apportent pas de solution à la question? stringByTrimmingCharactersInSet n'analyse ni l'iside de la chaîne, mais uniquement les bords. La réponse de Georg Sholly est parfaite.
Lukasz
3
Ce n'était pas exactement une réponse à la question, mais cela m'a certainement aidé. Merci
daveMac
1
Excellent code pour supprimer les espaces de début et de fin en même temps.
user523234
13

Avec une regex, mais sans besoin de framework externe:

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

theString = [theString stringByReplacingOccurrencesOfString:@" +" withString:@" "
                       options:NSRegularExpressionSearch
                       range:NSMakeRange(0, theString.length)];
MonsieurDart
la source
Vous auriez également alors encore besoin de couper le résultat, ou vous serez rempli d'espaces blancs. C'est probablement la réponse la plus simple, cependant.
lilbyrdie
2
la documentation pour NSRegularExpressionSearchdit que cela ne fonctionne qu'avec les rangeOfString:...méthodes
user102008
9

Une solution en une seule ligne:

NSString *whitespaceString = @" String with whitespaces ";

NSString *trimmedString = [whitespaceString
        stringByReplacingOccurrencesOfString:@" " withString:@""];
DeuxBeerGuy
la source
2
M'a aidé :). Merci pour ça!
thedom
5
Bien que cela soit utile, cela supprime tous les espaces. L'OP veut essentiellement un compactage d'espaces blancs, par exemple un découpage suivi d'une réduction des espaces blancs consécutifs en un seul espace blanc.
lilbyrdie
Autre remarque, cette solution ne traite pas des tabulations, des retours à la ligne ou des espaces blancs autres que les espaces.
fwielstra
2
Cela ne répond pas à l'OP, mais supprime à la place tous les espaces de la chaîne, vous vous retrouvez donc avec @ "Stringwithwhitespaces"
charles
6

Cela devrait le faire ...

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
la source
1
Cela fonctionne-t-il réellement avec la chaîne «a»? Il est de longueur 1, pour autant que je
sache
Oui, c'est la réponse que j'attendais. Merci +1
पवन
4

Une autre option pour regex est RegexKitLite , qui est très facile à intégrer dans un projet iPhone:

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

Essaye ça

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

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

Voici un extrait d'une NSStringextension, où se "self"trouve l' NSStringinstance. Il peut être utilisé pour réduire les espaces blancs contigus en un seul espace en transmettant [NSCharacterSet whitespaceAndNewlineCharacterSet]et ' 'aux deux arguments.

- (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;
}
démercredi
la source
-1

Solution alternative: procurez-vous une copie d'OgreKit (la bibliothèque d'expressions régulières Cocoa).

La fonction entière est alors:

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

Court et doux.

Si vous recherchez la solution la plus rapide, une série d'instructions soigneusement élaborées fonctionnera NSScannerprobablement mieux, mais cela ne sera nécessaire que si vous prévoyez de traiter d'énormes blocs de texte (plusieurs mégaoctets).

Matt Gallagher
la source
Y a-t-il une raison d'utiliser OgreKit au lieu de RegExKitLite? regexkit.sourceforge.net Il a un appel replaceOccurrencesOfRegex très similaire, et fonctionne au-dessus des bibliothèques RegEX existantes (je ne sais pas si Ogre est un moteur RegEX complet ou quoi)
Kendall Helmstetter Gelner
Je suis sûr que les deux fonctionneront. Je n'ai pas utilisé regexkit mais c'est une bonne suggestion à faire. Les gens devraient choisir en fonction des bibliothèques sous-jacentes: le pcre compatible PERL (RegExKitLite) et l'Oniguruma compatible Ruby (OgreKit).
Matt Gallagher
-1

selon @Mathieu Godart est la meilleure réponse, mais il manque une ligne, toutes les réponses réduisent juste l'espace entre les mots, mais si elles ont des tabulations ou ont une tabulation en place, comme ceci: "c'est du texte \ t, et \ tTab entre, ainsi de suite "en trois lignes de code, nous allons: la chaîne que nous voulons réduire les espaces blancs

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]];

le résultat est

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

sans remplacer l'onglet, le résultat sera:

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

Vous pouvez également utiliser un simple argument while. Il n'y a pas de magie RegEx là-dedans, alors c'est peut-être plus facile à comprendre et à modifier à l'avenir:

while([yourNSStringObject replaceOccurrencesOfString:@"  "
                         withString:@" "
                         options:0
                         range:NSMakeRange(0, [yourNSStringObject length])] > 0);
Sven-Steffen Arndt
la source
1
Ne répond pas à la question :) Il ne supprime pas les espaces de début et de fin.
hfossli
-1

Suivre deux expressions régulières fonctionnerait selon les besoins

  1. @ "+" pour faire correspondre les espaces blancs et les tabulations
  2. @ "\\ s {2,}" pour faire correspondre les espaces blancs, les tabulations et les sauts de ligne

Appliquez ensuite la méthode d'instance de nsstring stringByReplacingOccurrencesOfString:withString:options:range:pour les remplacer par un seul espace blanc.

par exemple

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

Remarque: je n'ai pas utilisé la bibliothèque 'RegexKitLite' pour la fonctionnalité ci-dessus pour iOS 5.x et supérieur.

Apalvai
la source
Cette solution ne supprime pas les espaces de début et de fin comme le demande l'OP.
hfossli
Les espaces de début / fin @hfossli peuvent être supprimés en appelant directement la méthode stringByTrimmingCharactersInSet: de NSString avec un jeu de caractères nouveau / ligne blanche. La solution ci-dessus consistait à supprimer les espaces redondants indépendamment de leur emplacement.
apalvai