正则表达式

正则表达式

纯文本做限制处理.可以用来检查一个字符串是否包含某种子串,将匹配的子串做替换或者从某个串中取出符合某个

作用:模式匹配(子串的定位操作),替换,效率高且简单.语法后台玩的比较溜,工作中不会的可以找他们.

  1. 数据验证
  2. 替换文本
  3. 提取子字符串

掌握正则表达式在OC代码中使用.

关键词: Regular Expression(正则表达式)
核心类: NSRegularExpression(NS框架下的,不需要导入):用来表达应用正则表达式.

注意点:

  1. 正则表达式很容易写错,所以一定要做错误处理
  2. 创建正则表达式.
  3. 查找相关内容.

- (void)regularExpression {
    NSString *content = @"蓝瘦, 香菇, 本来今天高高兴兴, 你为什么要说这种话, 蓝瘦, 在这里, 香菇! 第一次喂了一个女孩屎";
    //创建正则对象,配置参数
    // Pattern(模式), 要填的是`正则语法`所组成的`匹配模式`, 作用是告诉正则, 要查找的是什么("蓝瘦")
    NSString *pattren = @"香菇";
    // NSRegularExpressionOptions 正则表达式的匹配查找选项, 通常会给0, 因为正则语法可以实现这此功能
    // 错误处理,必须要做
    NSError *error;
    NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:pattren options:0 error:&error];
    if (error) {
        NSLog(@"创建正则失败");
    }
    
    
    /**
     // 查找第一次匹配结果
     参数一:在哪个字符串中匹配
     参数二:匹配查找选项,选0
     参数三:在这个字符串的哪个范围中匹配
     */
    NSTextCheckingResult *result = [regular firstMatchInString:content options:0 range:NSMakeRange(0, content.length)];
    NSLog(@"%@",NSStringFromRange(result.range));
    NSLog(@"%@",[content substringWithRange:result.range]);
    
    /**
     全部匹配
     参数1 NSString content
     参数2 0
     参数3 content的查找范围
     返回数组 results
     */
    NSArray<NSTextCheckingResult *> *results = [regular matchesInString:content options:0 range:NSMakeRange(0, content.length)];
    //遍历
    for (NSTextCheckingResult *result in results) {
        NSLog(@"%@",NSStringFromRange(result.range));
        NSLog(@"%@",[content substringWithRange:result.range]);
    }
}

目标:掌握一些正则的基本语法
  1. @"55555" -> @"5{5}" 中{}是功能性字符,表示重复5次
  2. @"5{3,7}" :{3,7}表示重复3~7次,会尽量找到多的.
  3. @"5+" :+表示至少有一个,默认只修饰前面一个
  4. @"(123)+" :()加小括号改变优先级,修饰一个整体.
  5. @"[136]" :[]代表组合,可以是其中的任意一个.
  6. 只要含数字: @"[0123456789]+" -> @"[0-9]+".-代表范围
  7. @"\d" :元字符(转义字符),\d在正则当中表示任意整数,\d等价[0-9]
    注意:OC的字符串中,\d正则不能直接写,所以要写\d.
  8. 找到字符:@"[a-z]+"
  9. @"\w":表示\w正则表示字符,汉字下划线,数字.OC中写\w
  10. @"\w和[\w]":在没有[]时,他表示的是匹配字符串的开始.^在[]里面,表示取反,表示并非是这个类型的字符串的开始.
    还要理解一下.
  11. @".com$": $表示匹配到字符串结束.
  12. @"(0|86)?" :表示以0或86或空(?).
  • 注意点
  • OC中\如果要代表字符串必须通过\来转义这个.才能使用.
  • 正则不能留空格,是一个字符在正则中来说是有意思的.pattern参数创建也不能加空格.都不能加空格.所以说错误处理一定要做.
正则练习
// 匹配QQ号码,匹配规则:全部是都是数字,第一个字符非0,长度为(6~11)
     ^[1-9]\\d{5,10}$
    // [^0],[1-9]    \d,[0-9]  {5,10}
    //    NSString *result = [@"48584958" firstStringMatchWithPattern:@"^[1-9]\\d{5,10}$"];
    //    NSLog(@"%@", result);
    
    // 匹配规则:以0或86或空开头,后面第一个数字为"1",当第二数字为 "3,5,8" 第三个数字为"0-9",当第二数字为"7" 第三个数字为"6或7或8",当第二个数字为"4"时,第三个数字为"5或7",手机号码位数为11位.
    // ^ (0|86)? 1 ( ([358][0-9]) | (7[678]) | 4[57] ) \d{8} $
    // ? 表示可有可无, 类似于bool
    NSString *result = [@"13800138000" firstStringMatchWithPattern:@"^(0|86)?1(([358][0-9])|(7[678])|4[57])\\d{8}$"];

提取分类文件保留.

正则实际用法:(重要),研究一下.

一种设计思想(都是用正则做的)
微信中的默认表情包的表情发送情况分析:

  • 表情是图片,图片始终要比文字大的多
  • 表情包在应用上本来就有,没有必要通过网路传输
  • 用一个特殊的字符串来表示表情,将该字符串发送出去
    • 不用发送图片,只发送文字,节省流量
    • 双方的应用本身已经拥有这套表情,可以直接显示出来
  1. 发送方与接收方, 规定一些特定的字符, 用来表示表情 如 [微笑] , /微笑
  2. 发送方: 在发消息之前, 将带有表情的文字转换成纯文字
    如: 你好!约吗(微笑表情) (富文本) --> 你好!约吗[smile.png] (纯文本)
  3. 接收方: 在收到消息后, 显示之前, 会做处理
    如: 你好!约吗[smile.png] --> 你好!约吗(微笑表情)

利用应用名来定义一份协议,再用正则来匹配协议.

微信扫二维码添加好友的思路分析:
微信扫描二维码的字符串
我先子定一个协议以Wechat://Action=Adduser?UserID=科比?message="你好我是谁谁谁,请求验证."

  • 利用正则来检测,是否为Wechat://开头,是的话,进行相应处理.
  1. 假设Action 表示 添加好友, 调用相关代码来实现功能
  2. 假设 UserID 表示添加的好友ID的参数, message 表示添加好友的消息的参数
  3. 调用添加好友的功能代码, 将相关参数给它.

二维码http://跳转网页的思路逻辑:

  • 利用正则来检测, 是否为http协议, 是用safari打开
    1. 获取参数, 利用相关代码, 让safari打开该网页

示例Demo:将表情图片名换成真正的图片名.

实现富文本(带有表情图片):富文本可以带附件NSTextAttachment类.

NSAttributedString

  1. 查找文本 -> 是否有表情图片的文字:正则表达式
  2. 利用富文本实现图文混排.

// [表情名] :[]在正则里面有特殊意义,所以\[表示普通的],正则转义
// [\w+]->转化为OC还要转义@"\[\w+\]"

  1. 正则查找图片格式字符串,获取到这个字符串.

  2. 转化为文字

  3. 富文本显示图片加文字.(替换表情字符串为图片附件字符串)

注意

  1. 表情符号的高度与Lable不匹配的解决办法.自定义类继承NSTextAttachment,一个快速的方法使其高度相等,** 修改它的y值,为-高度*0.2 **

  2. 多张表情图片的替换

注意数组越界问题:原因,因为替换的原理导致你的字符串的range减少,所以产生越界问题.但是还是以原来的来取.
解决办法,** 从尾部替换 **.

// 返回附件在它的容器当中的位置
- (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex
{
//继承系统的NSTextAttachment类.修改表情使其高度相同
    // 附件所处的容器的大小
    NSLog(@"lineFrag: %@", NSStringFromCGRect(lineFrag));
    // 附件在它的显示容器当中的位置
    NSLog(@"position: %@", NSStringFromCGPoint(position));
    // 附件所处文本在原始文本当中的位置(索引)
    NSLog(@"%zd", charIndex);
    
    // 返回的附件的大小, 与label的高度一样 (与文字接近)
    // 简单粗暴: -lineFrag.size.height * 0.2;  (StackOverFlow)
#pragma mark - 修改表情高度与Lable相同(开始会高一些)
    return CGRectMake(0, -lineFrag.size.height * 0.2, lineFrag.size.height, lineFrag.size.height);
    // 科学合理(不好解释): 要根据字体来决定该值
//    return CGRectMake(0, self.font.descender, lineFrag.size.height, lineFrag.size.height);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    self.label.text = @"蓝瘦, 香菇[smiley_1], 在这里, 第一次喂了一个女孩屎[smiley_6], 这么香菇[smiley_19]!";
    // 正则表达式只能针对纯文本NSString进行匹配, 不能NSAttributedString
    NSString *content = self.label.text;
    
    NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:content];
    
    // 1. 找到所有的图片(封装好了正则表达式)
    NSArray *rangeArray = [content matchesRangeWithPattern:@"\\[\\w+\\]"];
    if (rangeArray == nil) {
        return;
    }
    
    for (int i = 0; i < rangeArray.count; i++) {
        // 倒过来读取数组的元素
        NSValue *value = rangeArray[rangeArray.count - i - 1];
        // 每一个表情[表情图片]的范围
        NSRange range = value.rangeValue;
        
        // 获取每张图片图片
        UIImage *image = [UIImage imageNamed:[content substringWithRange:NSMakeRange(range.location + 1, range.length - 2)]];
        
        // 创建表情图片对应NSAttributedString
        HMTextAttament *attachment = [[HMTextAttament alloc] init];
        attachment.image = image;
        NSAttributedString *imageString = [NSAttributedString attributedStringWithAttachment:attachment];
        NSLog(@"%zd", imageString.length);
        
        // 替换文本
        [attrString replaceCharactersInRange:range withAttributedString:imageString];
    }
    
    // 已经全部替换完成
    self.label.attributedText = attrString;
}

  • ** 顺便学习一下文字换行和文字大小文字颜色的富文本处理. **
    思路:通过NSAttributedString的子类NSMutableAttributedString,设置前一段的字体属性,可以设置大小,颜色以及换行

** 注意:正则表达式只能匹配纯文本NSString,不能匹配NSAttributedString. **

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容