經驗之談—正則表達式實現圖文混排

  • 在項目中,我們經常需要發表情,以及經常需要將表情字符轉換成表情。因爲表情是一個圖片,所以我們發給服務器的時候,實際上是發一段特殊的文字給服務器,然後轉換成表情。以免浪費用戶過多的流量。
  • 那接下來,我們就來介紹一下,如何使用正則表達式實現圖文混排呢?
  • 爲了以後的代碼的管理方便,我們抽取出兩個類:

NSString+Regular.h中,我們暴露兩個方法出來:

/**
 *  返回正則表達式匹配的第一個結果
 *
 *  @param pattern 正則表達式
 *
 *  @return 匹配的第一個結果 是NSTextCheckingResult類型
 */
- (NSTextCheckingResult *)firstMacthWithPattern:(NSString *)pattern;

- (NSArray <NSTextCheckingResult *> *)machesWithPattern:(NSString *)pattern;

NSString+Regular.m中,我們實現一下這兩個方法:


- (NSTextCheckingResult *)firstMacthWithPattern:(NSString *)pattern
{
    //正則表達式的創建很容易失敗,注意捕獲錯誤
    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;
}

看一下效果:
正則

正則表情

發佈了177 篇原創文章 · 獲贊 111 · 訪問量 47萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章