2011-08-11 12 views
27

Hay una subcadena que se produce en una cadena varias veces. Yo uso rangeOfString, pero parece que solo puede encontrar la primera ubicación. ¿Cómo puedo encontrar todas las ubicaciones de la subcadena?Buscar todas las ubicaciones de subcadena en NSString (no solo primero)

NSString *subString1 = @"</content>"; 
NSString *subString2 = @"--\n"; 
NSRange range1 = [newresults rangeOfString:subString1]; 
NSRange range2 = [newresults rangeOfString:subString2]; 
int location1 = range1.location; 
int location2 = range2.location; 
NSLog(@"%i",location1); 
NSLog(@"%i",location2); 
+0

declaración se hace la pregunta más clara ... –

+1

Me gustaría ver [NSRegularExpressions] [1] [1]: http://stackoverflow.com/questions/4353834/search-through-nsstring-using- expresión-normal – EricS

Respuesta

70

Puede utilizar rangeOfString:options:range: y establecer el tercer argumento para estar más allá del alcance de la primera ocurrencia. Por ejemplo, se puede hacer algo como esto:

NSRange searchRange = NSMakeRange(0,string.length); 
NSRange foundRange; 
while (searchRange.location < string.length) { 
    searchRange.length = string.length-searchRange.location; 
    foundRange = [string rangeOfString:substring options:nil range:searchRange]; 
    if (foundRange.location != NSNotFound) { 
     // found an occurrence of the substring! do stuff here 
     searchRange.location = foundRange.location+foundRange.length; 
    } else { 
     // no more substring to find 
     break; 
    } 
} 
+4

Esto supone que las apariencias de subcadena no se superponen, lo cual es razonable teniendo en cuenta la pregunta. En general, puede no ser una suposición razonable. Considere el pajar "ababab". La aguja "abab" aparece en la posición 0 y en la posición 2 (solapando la aguja en la posición 0). La posición 2 sería ignorada por el algoritmo anterior. – kevinlawler

+3

Al cambiar el texto "+ foundRange.length" al texto "+1", se modifica el algoritmo de la forma adecuada. – kevinlawler

1

Pasando cero a [cadena rangeOfString: opciones de subcadenas: gama nula: searchRange]; muestra una advertencia.

para deshacerse de la advertencia, puesto en una enumeración de este grupo

enum { 
    NSCaseInsensitiveSearch = 1, 
    NSLiteralSearch = 2, 
    NSBackwardsSearch = 4, 
    NSAnchoredSearch = 8, 
    NSNumericSearch = 64, 
    NSDiacriticInsensitiveSearch = 128, 
    NSWidthInsensitiveSearch = 256, 
    NSForcedOrderingSearch = 512, 
    NSRegularExpressionSearch = 1024 
}; 

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/index.html#//apple_ref/doc/constant_group/Search_and_Comparison_Options

0

He aquí una versión en Swift 2.2 de la respuesta de pengone con el aporte de kevinlawler y Gibtang

Nota: la cadena y la subcadena son del tipo NSString

let fullStringLength = (string as String).characters.count 
var searchRange = NSMakeRange(0, fullStringLength) 
while searchRange.location < fullStringLength { 
    searchRange.length = fullStringLength - searchRange.location 
    let foundRange = string.rangeOfString(substring as String, options: .CaseInsensitiveSearch, range: searchRange) 
    if foundRange.location != NSNotFound { 
     // found an occurrence of the substring! do stuff here 
     searchRange.location = foundRange.location + 1 
    } else { 
     // no more strings to find 
     break 
    } 
} 
2

Esta es mi solución. Básicamente, el algoritmo atraviesa la cadena buscando coincidencias de subcadenas y devuelve esas coincidencias en una matriz.

Dado que NSRange es una estructura, no se puede agregar directamente a la matriz. Al usar NSValue, puedo codificar la coincidencia primero y luego agregarlo a la matriz. Para recuperar el rango, entonces decodificarNSValue objeto a NSRange.

#import <Foundation/Foundation.h> 

NSRange makeRangeFromIndex(NSUInteger index, NSUInteger length) { 
    return NSMakeRange(index, length - index); 
} 

NSArray<NSValue *> * allLocationsOfStringMatchingSubstring(NSString *text, NSString *pattern) { 
    NSMutableArray *matchingRanges = [NSMutableArray new]; 
    NSUInteger textLength = text.length; 
    NSRange match = makeRangeFromIndex(0, textLength); 

    while(match.location != NSNotFound) { 
     match = [text rangeOfString:pattern options:0L range:match]; 
     if (match.location != NSNotFound) { 
      NSValue *value = [NSValue value:&match withObjCType:@encode(NSRange)]; 
      [matchingRanges addObject:value]; 
      match = makeRangeFromIndex(match.location + 1, textLength); 
     } 
    } 

    return [matchingRanges copy]; 
} 

int main(int argc, const char * argv[]) { 
    @autoreleasepool { 
     NSString *text = @"TATACCATGGGCCATCATCATCATCATCATCATCATCATCATCACAG"; 
     NSString *pattern = @"CAT"; 
     NSArray<NSValue *> *matches = allLocationsOfStringMatchingSubstring(text, pattern); 

     NSLog(@"Text: %@", text); 
     NSLog(@"Pattern: %@", pattern); 
     NSLog(@"Number of matches found: %li", matches.count); 

     [matches enumerateObjectsUsingBlock:^(NSValue *obj, NSUInteger idx, BOOL *stop) { 
      NSRange match; 
      [obj getValue:&match]; 
      NSLog(@" Match found at index: %li", match.location); 
     }]; 
    } 
    return 0; 
} 
0

Swift 3,0

Buscar todas las ubicaciones de subcadena i

let text = "This is the text and i want to replace something" 
let mutableAttributedString = NSMutableAttributedString(string: text) 

var searchRange = NSRange(location: 0, length: text.characters.count) 
var foundRange = NSRange() 
while searchRange.location < text.characters.count { 
    searchRange.length = text.characters.count - searchRange.location 
    foundRange = (text as NSString).range(of: "i", options: NSString.CompareOptions.caseInsensitive, range: searchRange) 
    if foundRange.location != NSNotFound { 
     // found an occurrence of the substring! do stuff here 
     searchRange.location = foundRange.location + foundRange.length 
     mutableAttributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: foundRange) 
    } 
    else { 
     // no more substring to find 
     break 
    } 
} 

//Apply 
textLabel.attributedText = mutableAttributedString; 

y esto output-

enter image description here

Cuestiones relacionadas