经验之谈—正則表達式实现图文混排

  • 在项目中,我们常常须要发表情,以及常常须要将表情字符转换成表情。由于表情是一个图片。所以我们发给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;
}

看一下效果:
正则

正则表情

posted on 2017-07-29 21:29  ljbguanli  阅读(367)  评论(0编辑  收藏  举报