preface

The original link: kukumalucn. Making. IO/blog / 2018/1… My Demo set: JXT_iOS_Demos, like please star

In development, we deal with rich text from time to time. Sometimes, we need to use rich text to highlight a keyword in a sentence, and if the keyword appears only once, or if the sentence is short, Using the – (NSRange)rangeOfString:(NSString *)searchString method, you can easily determine the range of these keywords, or even write the range as a fixed value for a fixed sentence. But if it’s an article, it’s a little trickier. There are many related algorithms and even tripartite libraries on the Internet, such as ICTextView. The following provides a very simple system API-based method to solve this problem. The effect is as follows:

Code

– (NSRange)rangeOfString:(NSString *)searchString can only get the range of the first substring. If you set NSStringCompareOptions, you can change the result, but only one result can be obtained. Simple algorithm is traversal, online there are a lot of people provide code, but most of them are repeated traversal, efficiency will not so good, after debugging and optimization, the author has the following methods, validated by tens of thousands of character string matching, still can keep in the millisecond, should be applicable to most of the simple scenario, the main algorithm is compared with the regular or other way, Easy to understand:

- (void)jxt_enumerateRangeOfString:(NSString *)searchString usingBlock:(void(^) (NSRange searchStringRange, NSUInteger idx, BOOL *stop))block
{
    if ([self isKindOfClass:[NSString class&&]]self.length &&
        [searchString isKindOfClass:[NSString class]] && searchString.length) {
        NSArray <NSString *>*separatedArray = [self componentsSeparatedByString:searchString];
        if (separatedArray.count < 2) {
            return ;
        }
        NSUInteger count = separatedArray.count - 1; // Do it less often, because after splitting, the last part is useless
        NSUInteger length = searchString.length;
        __block NSUInteger location = 0;
        [separatedArray enumerateObjectsUsingBlock:^(NSString * _Nonnull componentString, NSUInteger idx, BOOL * _Nonnull stop) {
            if (idx == count) {
                *stop = YES;
            }
            else {
                location += componentString.length; // Skip the length before the filter string
                if (block) {
                    block(NSMakeRange(location, length), idx, stop);
                }
                location += length; // Skip the length of the filter string}}]; }}Copy the code

Specific use is as follows:

[attributedString.string jxt_enumerateRangeOfString:searchString usingBlock:^(NSRange searchStringRange, NSUInteger idx, BOOL *stop) {
    [attributedString addAttributes:@{
                                      NSForegroundColorAttributeName: [UIColor redColor],
                                      NSBackgroundColorAttributeName: [[UIColor blueColor] colorWithAlphaComponent:0.2],
                                      } range:searchStringRange];
}];
Copy the code

In this paper, the author: lam Wei this article links: kukumalucn. Making. IO/blog / 2018/1… Copyright Notice: All articles on this blog are licensed under CC BY-NC-ND 4.0 unless otherwise stated. Reprint please indicate the source!