6

I am trying to make multiple occurrences in a attributed string bold using something like the following

[attrStr setFont:[UIFont ...] range:[attrStr.string rangeOfString:@"hello world"]];

As you know, 'rangeOfString' always return the FIRST occurrence of the match... I am still quite new to iOS, just wondering what's the best way to set all occurrences to bold... Is there any function provided in NSString or something?

Thanks in advance!

Koolala
  • 347
  • 6
  • 15

3 Answers3

24

You should first try to get all ranges in the string and then set the attribute for every range. There are some great code examples right here on stackoverflow: https://stackoverflow.com/a/4653266/381870

Edit:

Here's an example for you

- (NSArray *)rangesOfString:(NSString *)searchString inString:(NSString *)str {
    NSMutableArray *results = [NSMutableArray array];
    NSRange searchRange = NSMakeRange(0, [str length]);
    NSRange range;
    while ((range = [str rangeOfString:searchString options:0 range:searchRange]).location != NSNotFound) {
        [results addObject:[NSValue valueWithRange:range]];
        searchRange = NSMakeRange(NSMaxRange(range), [str length] - NSMaxRange(range));
    }
    return results;
}

Usage:

NSArray *results = [self rangesOfString:@"foo" inString:@"foo bar foo"];
NSLog(@"%@", results);

gives you

(
    "NSRange: {0, 3}",
    "NSRange: {8, 3}"
)
Community
  • 1
  • 1
tim
  • 1,682
  • 10
  • 18
1

Converting Tim's answer to Swift 4:

extension NSString {
    open func ranges(of searchString: String) -> [NSRange] {
        var ranges = [NSRange]()
        var searchRange = NSRange(location: 0, length: self.length)
        var range: NSRange = self.range(of: searchString)
        while range.location != NSNotFound {
            ranges.append(range)
            searchRange = NSRange(location: NSMaxRange(range), length: self.length - NSMaxRange(range))
            range = self.range(of: searchString, options: [], range: searchRange)
        }
        return ranges
    }
}

Also did it to Swift's String primitive:

extension String {
    func ranges(of substring: String, options: CompareOptions = [], locale: Locale? = nil) -> [Range<Index>] {
        var ranges: [Range<Index>] = []
        while let range = self.range(of: substring, options: options, range: (ranges.last?.upperBound ?? self.startIndex)..<self.endIndex, locale: locale) {
            ranges.append(range)
        }
        return ranges
    }
}
RodolfoAntonici
  • 1,555
  • 21
  • 34
0

You will like have to use NSScanner to scan through the text and replace it.You can find an example for NSScanner here.

Community
  • 1
  • 1
Vignesh
  • 10,205
  • 2
  • 35
  • 73
  • Thanks @Vignesh for the info. I will take a look at this option... I chose the above solution because it's kinda more consistent with my current codebase. :) – Koolala Mar 13 '12 at 00:52