2011-08-25 11 views
7

Tengo una cadena de búsqueda, donde las personas pueden usar comillas para agrupar frases, y mezclar esto con palabras clave individuales. Por ejemplo, una cadena como esta:Separación de NSString en NSArray, pero permitiendo cotizaciones para agrupar palabras

"Something amazing" rooster 

me gustaría separar de que en un NSArray, por lo que tendría Something amazing (sin comillas) como uno de los elementos, y rooster como el otro.

Ni componentsSeparatedByString ni componentsSeparatedByCharactersInSet parecen ajustarse a la factura. ¿Hay alguna manera fácil de hacerlo, o debería codificarlo solo?

+0

Es posible que tenga un poco de suerte con NSRegularExpression, a pesar de dar con un regu fiable La expresión lar para esta tarea puede ser imposible. :-) Otro enfoque podría ser simplemente dividir en espacio (@ ""), luego examinar cada palabra buscando palabras que comienzan o terminan con una cita y combinarlas en una sola frase. –

Respuesta

1

Terminé yendo con una expresión regular porque ya estaba usando RegexKitLite y creando esta categoría NSString + SearchExtensions.

.h:

// NSString+SearchExtensions.h 
#import <Foundation/Foundation.h> 
@interface NSString (SearchExtensions) 
-(NSArray *)searchParts; 
@end 

.m:

// NSString+SearchExtensions.m 
#import "NSString+SearchExtensions.h" 
#import "RegexKitLite.h" 

@implementation NSString (SearchExtensions) 

-(NSArray *)searchParts { 
    __block NSMutableArray *items = [[NSMutableArray alloc] initWithCapacity:5]; 

    [self enumerateStringsMatchedByRegex:@"\\w+|\"[\\w\\s]*\"" usingBlock: ^(NSInteger captureCount, 
     NSString * const capturedStrings[captureCount], 
     const NSRange capturedRanges[captureCount], 
     volatile BOOL * const stop) { 

     NSString *result = [capturedStrings[0] stringByReplacingOccurrencesOfRegex:@"\"" withString:@""]; 

     NSLog(@"Match: '%@'", result); 
     [items addObject:result]; 
    }];   
    return [items autorelease]; 
} 
@end 

Esto devuelve un NSArray de cuerdas con las cadenas de búsqueda, la eliminación de las comillas dobles que rodean a las frases.

+0

Gracias, Tim. Simple, y funciona como un encanto. Debe soltar la opción 'autorelease' para las nuevas versiones de iOS, pero es realmente genial. Y es _way_ más útil que la respuesta "bricolaje" del otro Tim :) – mgarciaisaia

2

Probablemente tendrá que codificar algo de esto usted mismo, pero el NSScanner debe ser una buena base sobre la cual construir. Si usa el método scanUpToCharactersInSet para buscar todo hasta su próximo espacio en blanco o un carácter de comillas, puede seleccionar palabras. Una vez que encuentras un personaje bastante, puedes continuar escaneando usando solo la comilla en el conjunto de caracteres para finalizar, de modo que los espacios dentro de las comillas no den como resultado el final de un token.

+0

Si se siente triste por esta respuesta, vea la respuesta del OP [aquí] (http://stackoverflow.com/a/7379286/641451) con una solución funcional. – mgarciaisaia

0

correría -componentsSeparatedByString:@"\"" en primer lugar, a continuación, crear un BOOL isPartOfQuote, inicializado a YES si el primer carácter de la cadena era una", pero se establezca lo contrario en NO

A continuación, crear una matriz mutable para volver:. NSMutableArray* masterArray = [[NSMutableArray alloc] init];

a continuación, crear un bucle sobre la matriz devuelta de la separación:.

for(NSString* substring in firstSplitArray) { 
    NSArray* secondSplit; 
    if (isPartOfQuote == NO) { 
     secondSplit = [substring componentsSeparatedByString:@" "]; 
    } 
    else { 
     secondSplit = [NSArray arrayWithObject: substring]; 
    } 

    [masterArray addObjectsFromArray: secondSplit]; 
    isPartOfQuote = !isPartOfQuote; 
} 

Entonces volver masterArray de la función de

1

Si permite un enfoque ligeramente diferente, puede probar Dave DeLong's CHCSVParser. Se pretende analizar cadenas de CSV, pero si configura el carácter de espacio como el delimitador, estoy bastante seguro de que obtendrá el comportamiento deseado.

Como alternativa, puede echar un vistazo al código y ver cómo maneja los campos entre comillas, se publica bajo la licencia de MIT.

+3

+1 por razones obvias –

+0

@DaveDeLong, me tomó un poco de tiempo encontrar la "razón obvia": P –

1

Hice una forma sencilla de hacer esto utilizando NSScanner:

+ (NSArray *)arrayFromTagString:(NSString *)string { 

NSScanner *scanner = [NSScanner scannerWithString:string]; 
NSString *substring; 
NSMutableArray *array = [[NSMutableArray alloc] init]; 

while (scanner.scanLocation < string.length) { 

    // test if the first character is a quote 
    unichar character = [string characterAtIndex:scanner.scanLocation]; 
    if (character == '"') { 
     // skip the first quote and scan everything up to the next quote into a substring 
     [scanner setScanLocation:(scanner.scanLocation + 1)]; 
     [scanner scanUpToString:@"\"" intoString:&substring]; 
     [scanner setScanLocation:(scanner.scanLocation + 1)]; // skip the second quote too 
    } 
    else { 
     // scan everything up to the next space into the substring 
     [scanner scanUpToString:@" " intoString:&substring]; 
    } 
    // add the substring to the array 
    [array addObject:substring]; 

    //if not at the end, skip the space character before continuing the loop 
    if (scanner.scanLocation < string.length) [scanner setScanLocation:(scanner.scanLocation + 1)]; 
} 
return array.copy; 

}

Este método será convertir la matriz de nuevo a una cadena de etiqueta, vuelve a citar las palabras múltiples tags:

+ (NSString *)tagStringFromArray:(NSArray *)array { 

NSMutableString *string = [[NSMutableString alloc] init]; 
NSRange range; 

for (NSString *substring in array) { 
    if (string.length > 0) { 
     [string appendString:@" "]; 
    } 
    range = [substring rangeOfString:@" "]; 
    if (range.location != NSNotFound) { 
     [string appendFormat:@"\"%@\"", substring]; 
    } 
    else [string appendString:substring]; 
} 
return string.description; 

}

Cuestiones relacionadas