前言
最近项目中在做一个搜索的功能,要求搜索出来的内容要匹配搜索关键字高亮显示,三套方案:
-
对于搜索的关键字全部高亮显示,比如说搜“你好朋友”,只要有这四个字的词就高亮显示。(这一套方案完全匹配,过于古板)
-
后台直接返回html,前端用webview接收。(cell上加webview......)
-
后台对于搜索的关键字进行拆分,对于想要高亮的部分用标签分离出来,前端根据标签来进行高亮显示。(这种方案比较灵活,对于想要高亮的字加上标签,就可以实现高亮,选择着一种方案)
以下为案例代码:
这个str是数据源
NSString *str = @"啦啦啦<em>哈</em>费大幅度发哈哈哈哈哈哈费大幅度<em>嗯好</em>发动机大幅度嗯<em>哈哈</em>的方法哈哈哈哈哈哈费大幅度<em>嗯</em>凤飞飞的嗯嗯嫩恩恩哈哈哈哈”;
这个label用来接收处理好的text
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(50, 100, 200, 600)];
label.numberOfLines = 0;
label.attributedText = [self attributeString:str?str:@""];
[self.view addSubview:label];
处理<em></em>标签
//得到最后的NSMutableAttributedString
- (NSMutableAttributedString *)attributeString:(NSString *)string{
NSMutableArray *array = [NSMutableArray arrayWithCapacity:0];
NSArray *arr = [string componentsSeparatedByString:@"</em>"];
for (int i = 0; i < arr.count; i++) {
NSString *str = arr[i];
if ([str containsString:@">"]) {
NSRange range = [str rangeOfString:@">"];
NSString *strResult = [str substringFromIndex:range.location + range.length];
NSRange strRange = [str rangeOfString:[NSString stringWithFormat:@">%@", strResult]];//删除标签之前的">高亮文字"的range
NSRange resultStrRange = NSMakeRange(strRange.location + 1 - 4, strRange.length - 1);//删除标签之后的高亮文字range
if (i == 0) {
NSDictionary *dic = @{@"location":@(resultStrRange.location), @"length":@(resultStrRange.length)};
[array addObject:dic];
}else{
NSDictionary *dic = array[i - 1];
NSDictionary *resultDic = @{@"location":@(resultStrRange.location + [dic[@"location"] integerValue]+ [dic[@"length"] integerValue]), @"length":@(resultStrRange.length)};
[array addObject:resultDic];
}
}
}
NSMutableAttributedString *attString = [[NSMutableAttributedString alloc]initWithString:[self getDeletedTagStringwithString:string]];
for (int i = 0; i < array.count; i++) {
NSRange range = NSMakeRange([array[i][@"location"] integerValue], [array[i][@"length"] integerValue]);
[attString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:range];
}
return attString;
}
删除字符串里面的标签
//删除字符串里面的标签
- (NSString *)getDeletedTagStringwithString:(NSString *)string{
NSRegularExpression *regularExpretion = [NSRegularExpression regularExpressionWithPattern:@"<[^>]*>|\n" options:0 error:nil];
string = [regularExpretion stringByReplacingMatchesInString:string options:NSMatchingReportProgress range:NSMakeRange(0, string.length) withTemplate:@""];
return string;
}
表现结果:

更新:2018年8月30号
前言:发现上面那个种方式有个问题,就是当输入内容中包含/br等标签的时候,也会被getDeletedTagStringwithString
方法给删除,这时候上面算的range会出现错误,就会崩溃,这样的代码健壮性有待提高,下面放上修改后的代码,提高代码的鲁棒性和健壮性是必须的!
修改思路:这里的思路是,先给原带有标签的字符串需要高亮的部分的rnage获得到,然后直接在原字符串的基础上给这个range高量显示,最后在删除<em></em>标签,这样做可以有效避免因为有其它标签或者其他内容先删除后高亮导致的崩溃
// 高亮文字(搜索结果包含关键字)
+ (NSMutableAttributedString *)getAttributeStrWithString:(NSString *)string{
NSMutableArray *array = [NSMutableArray arrayWithCapacity:0];
// //测试数据
// string = @"<em>1<em>哈>2</em>啦和<em>1<em>啦啦啦</em>取值";
// string = @"哈>2";
// string = @"ha<em>哈>2";
// string = @"ha</em>哈>2";
// string = @"/br1</em>2<em>3>4</em>5<em>6<em>7>8</em>9";
// string = @"1</em>2<em>3>4</em>5<em><em>6<em>7>8</em>9";
// string = @"0</em>1</em>2<em>3>4</em>5<em><em>6<em>7>8</em>9";
// string = @"0</em>1</em>2<em>3>4</em>5<em><em>6<em>7>8</em>";
// string = @"</em>2<em>3>4</em>5<em><em>6<em>7>8</em></em>9</em>";
// string = @"";
#warning --- 换成在有<em>的标签内先高亮显示,然后在去标签,这个搜索随笔的cell的高度计算也需要调整
if ([string containsString:@"</em>"]) {
NSArray *arr = [string componentsSeparatedByString:@"</em>"];
for (int i = 0; i < arr.count; i++) {
NSString *str = arr[i];
if ([str containsString:@"<em>"]) {
NSMutableArray *rangeArray = [self rangeOfSubString:@"<em>" inString:str];
NSRange range = [rangeArray.lastObject rangeValue];
NSString *strResult = [str substringFromIndex:range.location + range.length];//高亮的文字"哈>2"
NSRange strRange = [str rangeOfString:[NSString stringWithFormat:@">%@", strResult]];//高亮文字加一个>的range,也就是">哈>2"的range
NSRange resultStrRange = NSMakeRange(strRange.location + 1, strRange.length - 1);//高亮文字range
#warning --- array.count=0的时候有问题
if (i == 0) {
NSDictionary *dic = @{@"location":@(resultStrRange.location), @"length":@(resultStrRange.length)};
[array addObject:dic];
}else{
if (array.count > 0) {
NSDictionary *dic = array[array.count - 1];
NSDictionary *resultDic = @{@"location":@(resultStrRange.location + [dic[@"location"] integerValue]+ [dic[@"length"] integerValue] + 5), @"length":@(resultStrRange.length)};//第二个开始的range都是在前一个rang的基础上累加的
[array addObject:resultDic];
}else{
int nLength = 0;
for (int m = 0; m < i; m++) {
nLength = nLength + (int)[arr[m] length] + 5;
}
NSDictionary *dic = @{@"location":@(resultStrRange.location + nLength), @"length":@(resultStrRange.length)};//[arr[i - 1] length] + 5指的是数组前一个字符串的长度+</em>的长度
[array addObject:dic];
}
}
}
}
}
NSMutableAttributedString *attString = [[NSMutableAttributedString alloc]initWithString:string];
for (int i = 0; i < array.count; i++) {
NSRange range = NSMakeRange([array[i][@"location"] integerValue], [array[i][@"length"] integerValue]);
@try {
if (attString.length >= (range.length + range.location)) {
[attString addAttribute:NSForegroundColorAttributeName value:kColor_CG range:range];
}
} @catch (NSException *exception) {
[YSLogUtils logError:[NSString stringWithFormat:@"UILabel+Frame的 根据NSRange高亮显示的地方崩溃,内容是:%@", string] errorDict:nil];
}
}
return [self getDeletedTagStringwithString:attString andArray:array];
}
+ (NSMutableAttributedString *)getDeletedTagStringwithString:(NSMutableAttributedString *)attributeString andArray:(NSMutableArray *)array{
NSMutableAttributedString *attString = attributeString;
for (int i = 0; i < array.count; i++) {
NSRange range1 = NSMakeRange([array[i][@"location"] integerValue] - 4 - (4 + 5) * i, 4);//高亮文字前面的<em>的range
[attString deleteCharactersInRange:range1];
NSRange range2 = NSMakeRange([array[i][@"location"] integerValue] + [array[i][@"length"] integerValue] - 5 * i - 4 * (i + 1), 5);//高亮文字前面的</em>的range(删除<em>之后,所以location要-4)
[attString deleteCharactersInRange:range2];
}
return attString;
}
+ (NSMutableArray *)rangeOfSubString:(NSString*)subStr inString:(NSString*)string {
NSMutableArray *rangeArray = [NSMutableArray arrayWithCapacity:0];
NSString *string1 = [string stringByAppendingString:subStr];//防止数组越界,崩溃的
NSString *temp;
for(int i = 0; i < string.length; i++) {
temp = [string1 substringWithRange:NSMakeRange(i, subStr.length)];
if ([temp isEqualToString:subStr]) {
NSRange range = {i, subStr.length};
[rangeArray addObject: [NSValue valueWithRange:range]];
}
}
return rangeArray;
}
网友评论