Find all locations of substring in NSString (not just first)
You can use rangeOfString:options:range:
and set the third argument to be beyond the range of the first occurrence. For example, you can do something like this:
NSRange searchRange = NSMakeRange(0,string.length);NSRange foundRange;while (searchRange.location < string.length) { searchRange.length = string.length-searchRange.location; foundRange = [string rangeOfString:substring options:0 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; }}
Swift 3.0
Find all locations of substring 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 }}//ApplytextLabel.attributedText = mutableAttributedString;
And this output-
This is my solution. Basically, the algorithm traverses the string looking for substring matches and returns those matches in an array.
Since an NSRange is a struct it cannot be added to the array directly. By using NSValue, I can encode the match first and then add it to the array. To retrieve the range, I then decode the NSValue object to an 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;}