GMHighlightStrGenerator.m 4.33 KB
//
//  GMHighlightStrGenerator.m
//  GMKit
//
//  Created by wangyang on 2020/4/14.
//

#import "GMHighlightStrGenerator.h"

@implementation GMHighlightStrGenerator

- (void)debugConfig {
    NSAssert(self.hightlightColor, @"GMHighlightStrGenerator.hightlightColor不可以为空");
    NSAssert(self.normalColor, @"GMHighlightStrGenerator.normalColor不可以为空");
    NSAssert(self.hightlightFont, @"GMHighlightStrGenerator.hightlightFont不可以为空");
    NSAssert(self.font, @"GMHighlightStrGenerator.font不可以为空");
}

- (nullable NSMutableAttributedString *)generateWithString:(NSString *)str {
    if (str.length == 0) {
        return nil;
    }

#ifdef DEBUG
    [self debugConfig];
#endif

    NSMutableAttributedString *resultAttrString = [self parseHighlight:str];

    // 创建一个NSMutableParagraphStyle,以便稍后复用
    NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
    style.lineSpacing = _lineHeight;
    style.lineBreakMode = NSLineBreakByTruncatingTail;
    style.alignment = _aligment;

    if (resultAttrString.length > 0) {
        // 如果有高亮,resultAttrString不为空,那只加一个NSParagraphStyleAttributeName属性
        [resultAttrString addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, resultAttrString.length)];
    } else if (resultAttrString.length == 0) {
        // 如果没有走到正则里面,说明没有需要高亮的内容,设置普通颜色就好
        NSAttributedString *subString = [[NSAttributedString alloc] initWithString:str attributes:@{NSFontAttributeName : self.font, NSForegroundColorAttributeName:_normalColor, NSParagraphStyleAttributeName:style}];
        [resultAttrString appendAttributedString:subString];
    }
    return resultAttrString;
}

/// 解析出<ems>xxx</ems>,并将对应的 xxx 文本设置为高亮颜色
- (NSMutableAttributedString *)parseHighlight:(NSString *)str {
    NSError *error;
    NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"([\\w\\W]*)<ems>([\\w\\W]+)<\\/ems>([\\w\\W]*)" options:0 error:&error];
    if (error) {
        return nil;
    }

    NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] init];
    [expression enumerateMatchesInString:str options:0 range:NSMakeRange(0, str.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {

        // 根据NSTextCheckingResult的rangeAtIndex方法文档
        // result至少会有一个range,这个range是匹配它自身全部的,所以正则匹配的其它range是从1开始的
        // <ems></ems>将string分隔为如下三个部分
        // string1:对应<ems>标签前的文本
        // string2:对应标签中的高亮文本
        // string3:对应</ems>标签后的文本

        NSString *string1 = [str substringWithRange:[result rangeAtIndex:1]];
        NSAttributedString *attrString1 = [self parseHighlight:string1];
        if (attrString1.length > 0) {
            [attString appendAttributedString:attrString1];
        }else{
            NSAttributedString *subString = [[NSAttributedString alloc] initWithString:string1 attributes:@{NSFontAttributeName : _font, NSForegroundColorAttributeName:_normalColor}];
            [attString appendAttributedString:subString];
        }

        NSString *string2 = [str substringWithRange:[result rangeAtIndex:2]];
        NSAttributedString *attrString2 = [self parseHighlight:string2];
        if (attrString2.length > 0) {
            [attString appendAttributedString:attrString2];
        }else{
            NSAttributedString *subString = [[NSAttributedString alloc] initWithString:string2 attributes:@{NSFontAttributeName : _hightlightFont, NSForegroundColorAttributeName:_hightlightColor}];
            [attString appendAttributedString:subString];
        }

        NSString *string3 = [str substringWithRange:[result rangeAtIndex:3]];
        NSAttributedString *attrString3 = [self parseHighlight:string3];
        if (attrString3.length > 0) {
            [attString appendAttributedString:attrString3];
        }else{
            NSAttributedString *subString = [[NSAttributedString alloc] initWithString:string3 attributes:@{NSFontAttributeName : _font, NSForegroundColorAttributeName:_normalColor}];
            [attString appendAttributedString:subString];
        }
    }];

    return attString;
}

@end