原文連接:kukumalucn.github.io/blog/2018/1…
本文Demo地址:Demo ,喜歡請star
個人Demo集合:JXT_iOS_Demos ,喜歡請stargit
平時開發中,咱們總會不時的和富文本打交道。有時,咱們須要用富文本高亮某句話中的某個關鍵字,若是這個關鍵字只出現一次,或者說這句話比較短,用- (NSRange)rangeOfString:(NSString *)searchString
這個方法就能夠很容易的肯定這些關鍵字的range
,若是是固定的一句話,那甚至能夠將range
寫成固定值。可是若是是一篇文章,就會相對棘手些。 這個問題其實很像是關鍵字檢索高亮的問題,網上有不少相關的算法甚至三方庫,好比 ICTextView ,下面提供一個十分簡單的基於系統API的方法來解決這個問題,效果以下:github
其實這個算法的核心就在於如何同時獲取到字符串中重複出現的全部的子串的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 許可協議。轉載請註明出處!ui