Contraiga secuencias de espacio en blanco en un solo carácter y recorte la cadena

122

Considere el siguiente ejemplo:

"    Hello      this  is a   long       string!   "

Quiero convertir eso a:

"Hello this is a long string!"
hfossli
fuente

Respuestas:

125

OS X 10.7+ y iOS 3.2+

Use la solución nativa de expresiones regulares proporcionada por hfossli.

De otra manera

Use su biblioteca de expresiones regulares favorita o use la siguiente solución nativa de Cocoa:

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
fuente
44
Tengo curiosidad por una comparación de rendimiento de esto con un reemplazo de expresiones regulares con un ajuste para eliminar los extremos. Por un lado, tienes que lidiar con una expresión regular. Por otro lado, tienes un predicado. Cualquiera de las dos requiere el procesamiento interno de las expresiones respectivas.
lilbyrdie
@lilbyrdie: Esto depende de la cadena, creo, cuántos espacios en blanco hay. Mi solución es bastante lenta, porque crea un nuevo objeto para cada subcadena y envía llamadas de método a cada una de ellas.
Georg Schölly
2
Buena respuesta, votada como tal, pero cuestiono su definición de "fácil". Atentamente, el ex tipo Python ahora en ObjC-land ;-)
JK Laiho
2
Me hiciste reír con 'no uses soluciones complejas si hay una fácil'. Entonces, el más fácil es [toBeTrimmed stringByReplacingOccurrencesOfString: @ "" withString: @ ""] ¿no? Todavía voté su respuesta, pero definitivamente es la más fácil
Mário Carvalho
2
@ MárioCarvalho La pregunta pregunta cómo eliminar el exceso de espacio en blanco, no todo.
swilliams 01 de
52

Regex y NSCharacterSet está aquí para ayudarlo. Esta solución recorta los espacios en blanco iniciales y finales, así como múltiples espacios en blanco.

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

El registro finalda

"Hello this is a long string!"

Posibles patrones alternativos de expresiones regulares:

  • Reemplazar solo espacio: [ ]+
  • Reemplazar espacio y pestañas: [ \\t]+
  • Reemplazar espacio, pestañas y líneas nuevas: \\s+

Resumen de rendimiento

La facilidad de extensión, el rendimiento, las líneas numéricas de código y la cantidad de objetos creados hacen que esta solución sea adecuada.

hfossli
fuente
3
hfossli's es la respuesta más elegante en mi libro. Además, acabo de enterarme de que puedes usar expresiones regulares en stringByReplacingOccurrencesOfString:. No puedo creer que no lo supiera.
davidf2281
1
Increíble. Trabajado como un encanto
Kushal Ashok
41

En realidad, hay una solución muy simple para eso:

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

( Fuente )

arikfr
fuente
29
Creo que esto eliminará solo los espacios iniciales y finales, y eliminará todos ellos. no tratará con "hola foo"
Brian Postow
2
d * mn terminaciones de línea y formateo automático ... no trata con "hola______foo" (asume _ -> "" porque formatear los comentarios es difícil)
Brian Postow
32
¿Por qué votan y responden, lo que no proporciona una solución a la pregunta? stringByTrimmingCharactersInSet no analiza el iside de la cadena sino solo los bordes. La respuesta de Georg Sholly es la perfecta.
Lukasz el
3
No fue exactamente una respuesta a la pregunta, pero seguro que me ayudó. Gracias
daveMac
1
Excelente código para eliminar el espacio inicial y final al mismo tiempo.
user523234
13

Con una expresión regular, pero sin la necesidad de ningún marco externo:

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

theString = [theString stringByReplacingOccurrencesOfString:@" +" withString:@" "
                       options:NSRegularExpressionSearch
                       range:NSMakeRange(0, theString.length)];
MonsieurDart
fuente
También necesitaría recortar el resultado, o se rellenará con espacios en blanco. Sin embargo, esta es probablemente la respuesta más simple.
lilbyrdie
2
la documentación NSRegularExpressionSearchdice que solo funciona con los rangeOfString:...métodos
user102008
9

Una solución de una línea:

NSString *whitespaceString = @" String with whitespaces ";

NSString *trimmedString = [whitespaceString
        stringByReplacingOccurrencesOfString:@" " withString:@""];
TwoBeerGuy
fuente
2
Me ayudó a salir :). ¡Gracias por eso!
thedom
55
Si bien esto es útil, elimina todos los espacios en blanco. El OP básicamente quiere la compactación de espacios en blanco, por ejemplo, un recorte seguido de la reducción de espacios en blanco consecutivos a un solo espacio en blanco.
lilbyrdie
Otra nota, esta solución no trata con pestañas o líneas nuevas o espacios en blanco que no sean espacios.
fwielstra
2
Esto no responde al OP, sino que elimina todos los espacios en la cadena, por lo que terminas con @ "Stringwithwhitespaces"
charles
6

Esto debería hacerlo ...

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
fuente
1
¿Esto realmente funciona con la cadena 'a'? Es de longitud 1, hasta donde puedo ver, esta solución filtrará todas las palabras divididas con tamaño 0 y 1.
fwielstra
Sí, esa es la respuesta que esperaba. Gracias +1
पवन
4

Otra opción para regex es RegexKitLite , que es muy fácil de integrar en un proyecto de iPhone:

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

Prueba esto

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

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

Aquí hay un fragmento de una NSStringextensión, donde "self"está la NSStringinstancia. Se puede utilizar para colapsar los espacios en blanco contigua en un único espacio mediante el paso en [NSCharacterSet whitespaceAndNewlineCharacterSet]y ' 'a los dos argumentos.

- (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
fuente
-1

Solución alternativa: obtenga una copia de OgreKit (la biblioteca de expresiones regulares de Cocoa).

Toda la función es entonces:

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

Corto y dulce.

Si buscas la solución más rápida, una serie de instrucciones cuidadosamente construidas NSScannerprobablemente funcionaría mejor, pero eso solo sería necesario si planeas procesar enormes (muchos megabytes) bloques de texto.

Matt Gallagher
fuente
¿Hay alguna razón para usar OgreKit en lugar de RegExKitLite? regexkit.sourceforge.net Tiene una llamada replaceOccurrencesOfRegex muy similar, y funciona en la parte superior de las bibliotecas RegEX existentes (no estoy seguro si Ogre es un motor RegEX completo o qué)
Kendall Helmstetter Gelner
Estoy seguro de que ambos funcionarán. No he usado regexkit pero es una buena sugerencia. Las personas deberían elegir según las bibliotecas subyacentes: el pcre compatible con PERL (RegExKitLite) y el Oniguruma compatible con Ruby (OgreKit).
Matt Gallagher el
-1

según @Mathieu Godart es la mejor respuesta, pero falta una línea, todas las respuestas solo reducen el espacio entre las palabras, pero cuando tienen pestañas o espacio en la pestaña, así: "esto es texto \ t, y \ tTab entre, etc. "en el código de tres líneas lo haremos: la cadena que queremos reducir espacios en blanco

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

el resultado es

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

sin reemplazar la pestaña, el resultado será:

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

También puede usar un argumento while simple. No hay magia RegEx allí, así que tal vez sea más fácil de entender y modificar en el futuro:

while([yourNSStringObject replaceOccurrencesOfString:@"  "
                         withString:@" "
                         options:0
                         range:NSMakeRange(0, [yourNSStringObject length])] > 0);
Sven-Steffen Arndt
fuente
1
No responde la pregunta :) No elimina los espacios en blanco iniciales y finales.
hfossli
-1

Seguir dos expresiones regulares funcionaría según los requisitos

  1. @ "+" para combinar espacios en blanco y pestañas
  2. @ "\\ s {2,}" para combinar espacios en blanco, tabulaciones y saltos de línea

Luego aplique el método de instancia de nsstring stringByReplacingOccurrencesOfString:withString:options:range:para reemplazarlos con un solo espacio en blanco.

p.ej

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

Nota: No utilicé la biblioteca 'RegexKitLite' para la funcionalidad anterior para iOS 5.xy superior.

apalvai
fuente
Esta solución no elimina los espacios en blanco iniciales y finales como pide el OP.
hfossli
Los espacios iniciales / finales de @hfossli se pueden eliminar llamando directamente a stringByTrimmingCharactersInSet de NSString: método con un nuevo conjunto de caracteres de línea blanca. La solución anterior fue eliminar los espacios redundantes independientemente de su ubicación.
apalvai