原文连接: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