经验之谈—正則表達式实现图文混排
- 在项目中,我们常常须要发表情,以及常常须要将表情字符转换成表情。由于表情是一个图片。所以我们发给server的时候,实际上是发一段特殊的文字给server,然后转换成表情。以免浪费用户过多的流量。
- 那接下来。我们就来介绍一下,怎样使用正則表達式实现图文混排呢?
- 为了以后的代码的管理方便,我们抽取出两个类:
NSString+Regular.h中。我们暴露两个方法出来:
/**
* 返回正則表達式匹配的第一个结果
*
* @param pattern 正則表達式
*
* @return 匹配的第一个结果 是NSTextCheckingResult类型
*/
- (NSTextCheckingResult *)firstMacthWithPattern:(NSString *)pattern;
- (NSArray <NSTextCheckingResult *> *)machesWithPattern:(NSString *)pattern;
NSString+Regular.m中,我们实现一下这两个方法:
- (NSTextCheckingResult *)firstMacthWithPattern:(NSString *)pattern
{
//正則表達式的创建非常easy失败,注意捕获错误
NSError *error = nil;
//依据正則表達式创建实例
NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
if ( error)
{
NSLog(@"正則表達式创建失败");
return nil;
}
//匹配出结果
NSTextCheckingResult *result = [regular firstMatchInString:self options:0 range:NSMakeRange(0, self.length)];
if ( result)
{
NSLog(@"匹配");
return result;
}else
{
NSLog(@"不匹配");
return nil;
}
}
- (NSArray <NSTextCheckingResult *> *)machesWithPattern:(NSString *)pattern
{
NSError *error = nil;
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
if (error)
{
NSLog(@"正則表達式创建失败");
return nil;
}
return [expression matchesInString:self options:0 range:NSMakeRange(0, self.length)];
}
我们进而对NSTextAttachment写一个子类
ZYTextAttachment.h 中 我们暴露一个方法出来:
@interface ZYTextAttachment : NSTextAttachment
- (instancetype)initWithImage:(UIImage *)image;
@end
ZYTextAttachment.m中。我们实现一下:
#import "ZYTextAttachment.h"
@implementation ZYTextAttachment
- (instancetype)initWithImage:(UIImage *)image
{
if (self = [super init])
{
self.image = image;
}
return self;
}
- (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex
{
return CGRectMake(0, -lineFrag.size.height * 0.2, lineFrag.size.height, lineFrag.size.height);
}
这样就能解决图片大写跟文字大小不一致的情况。
接下来。我们在viewController中。
- (void)viewDidLoad {
[super viewDidLoad];
self.label.text = @"二货[smiley_2], 你在干嘛呢[smiley_6] 一起吃饭?[smiley_44]!";
}
然后在以下的方法中:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSString *content = self.label.text;
//匹配表情文字
NSString *pattern = @"\\[\\w+\\]";
NSArray *resultArr = [content machesWithPattern:pattern];
if (!resultArr) return;
NSMutableAttributedString *attrContent = [[NSMutableAttributedString alloc]initWithString:content];
NSUInteger lengthDetail = 0;
//遍历全部的result 取出range
for (NSTextCheckingResult *result in resultArr) {
//取出图片名
NSString *imageName = [content substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)];
// 创建AttributeString, 来包装图片
ZYTextAttachment *attachment = [[ZYTextAttachment alloc]initWithImage:[UIImage imageNamed:imageName]];
// 将附近包装到NSAttributedString中
NSAttributedString *imageString = [NSAttributedString attributedStringWithAttachment:attachment];
//图片附件的文本长度是1
NSLog(@"%zd",imageString.length);
NSUInteger length = attrContent.length;
NSRange newRange = NSMakeRange(result.range.location - lengthDetail, result.range.length);
[attrContent replaceCharactersInRange:newRange withAttributedString:imageString];
lengthDetail += length - attrContent.length;
}
//更新到label上
self.label.attributedText = attrContent;
}
看一下效果: