iOS中一種字串關鍵字檢索高亮的簡易實現

霖溦發表於2019-02-27

前言

原文連結:kukumalucn.github.io/blog/2018/1…
本文Demo地址:Demo ,喜歡請star
我的Demo集合:JXT_iOS_Demos ,喜歡請star

平時開發中,我們總會不時的和富文字打交道。有時,我們需要用富文字高亮某句話中的某個關鍵字,如果這個關鍵字只出現一次,或者說這句話比較短,用- (NSRange)rangeOfString:(NSString *)searchString這個方法就可以很容易的確定這些關鍵字的range,如果是固定的一句話,那甚至可以將range寫成固定值。但是如果是一篇文章,就會相對棘手些。
這個問題其實很像是關鍵字檢索高亮的問題,網上有很多相關的演算法甚至三方庫,比如 ICTextView ,下面提供一個十分簡單的基於系統API的方法來解決這個問題,效果如下:

iOS中一種字串關鍵字檢索高亮的簡易實現

Code

其實這個演算法的核心就在於如何同時獲取到字串中重複出現的所有的子串的range- (NSRange)rangeOfString:(NSString *)searchString方法只能獲取到第一次出現的子串的range,設定NSStringCompareOptions,可以改變獲取到的結果,但是也只能獲取到一個,不知道系統有沒有提供直接的方法,筆者暫時是沒有發現……
簡單的演算法就是遍歷,網上也有很多人提供了程式碼,但大部分都是多次遍歷,效率肯定不會太好,經過除錯和優化,筆者有了如下方法,通過幾萬字的字串匹配驗證,依舊可以保持在毫秒級,應該是可以適用於大部分簡單的場景了,主要是演算法相對於正則或者其他方式,簡單易懂:

- (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; //少遍歷一次,因為拆分之後,最後一部分是沒用的
        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; //跳過待篩選串前面的串長度
                if (block) {
                    block(NSMakeRange(location, length), idx, stop);
                }
                location += length; //跳過待篩選串的長度
            }
        }];
    }
}
複製程式碼

具體使用如下:

[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];
}];
複製程式碼

本文作者: 霖溦
本文連結: kukumalucn.github.io/blog/2018/1…
版權宣告: 本部落格所有文章除特別宣告外,均採用 CC BY-NC-ND 4.0 許可協議。轉載請註明出處!

相關文章