正则表达式
纯文本做限制处理.可以用来检查一个字符串是否包含某种子串,将匹配的子串做替换或者从某个串中取出符合某个
作用:模式匹配(子串的定位操作),替换,效率高且简单.语法后台玩的比较溜,工作中不会的可以找他们
.
- 数据验证
- 替换文本
- 提取子字符串
掌握正则表达式在OC代码中使用.
关键词: Regular Expression(正则表达式)
核心类: NSRegularExpression(NS框架下的,不需要导入):用来表达
和应用
正则表达式.
注意点:
- 正则表达式很容易写错,所以一定要做错误处理
- 创建正则表达式.
- 查找相关内容.
- (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]);
}
}
目标:掌握一些正则的基本语法
- @"55555" -> @"5{5}" 中
{}
是功能性字符,表示重复5次 - @"5{3,7}" :
{3,7}
表示重复3~7次,会尽量找到多的. - @"5+" :
+
表示至少有一个,默认只修饰前面一个 - @"(123)+" :
()
加小括号改变优先级,修饰一个整体. - @"[136]" :
[]
代表组合,可以是其中的任意一个. - 只要含数字: @"[0123456789]+" -> @"[0-9]+".
-
代表范围 - @"\d" :元字符(转义字符),\d在正则当中表示任意整数,\d等价[0-9]
注意:OC的字符串中,\d正则不能直接写,所以要写\d. - 找到字符:@"[a-z]+"
- @"\w":表示\w正则表示字符,汉字下划线,数字.OC中写\w
- @"\w和[\w]":在没有[]时,他表示的是匹配字符串的开始.^在[]里面,表示取反,表示并非是这个类型的字符串的开始.
还要理解一下. - @".com$":
$
表示匹配到字符串结束. - @"(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}$"];
提取分类文件保留.
正则实际用法:(重要),研究一下.
一种设计思想(都是用正则做的)
微信中的默认表情包的表情发送情况分析:
- 表情是图片,图片始终要比文字大的多
- 表情包在应用上本来就有,没有必要通过网路传输
- 用一个特殊的字符串来表示表情,将该字符串发送出去
- 不用发送图片,只发送文字,节省流量
- 双方的应用本身已经拥有这套表情,可以直接显示出来
- 发送方与接收方, 规定一些
特定的字符
, 用来表示表情 如 [微笑] , /微笑 - 发送方: 在发消息之前, 将带有表情的文字转换成纯文字
如: 你好!约吗(微笑表情) (富文本) --> 你好!约吗[smile.png] (纯文本) - 接收方: 在收到消息后, 显示之前, 会做处理
如: 你好!约吗[smile.png] --> 你好!约吗(微笑表情)
利用应用名来定义一份协议,再用正则来匹配协议.
微信扫二维码添加好友的思路分析:
微信扫描二维码的字符串
我先子定一个协议以Wechat://Action=Adduser?UserID=科比?message="你好我是谁谁谁,请求验证."
- 利用正则来检测,是否为Wechat://开头,是的话,进行相应处理.
- 假设Action 表示 添加好友, 调用相关代码来实现功能
- 假设 UserID 表示添加的好友ID的参数, message 表示添加好友的消息的参数
- 调用添加好友的功能代码, 将相关参数给它.
二维码http://跳转网页的思路逻辑:
- 利用正则来检测, 是否为http协议, 是用safari打开
- 获取参数, 利用相关代码, 让safari打开该网页
示例Demo:将表情图片名换成真正的图片名.
实现富文本(带有表情图片):富文本可以带附件NSTextAttachment类.
NSAttributedString
- 查找文本 -> 是否有表情图片的文字:正则表达式
- 利用富文本实现图文混排.
// [表情名] :[]在正则里面有特殊意义,所以\[
表示普通的]
,正则转义
// [\w+]->转化为OC还要转义@"\[\w+\]"
正则查找图片格式字符串,获取到这个字符串.
转化为文字
富文本显示图片加文字.(替换表情字符串为图片附件字符串)
注意
表情符号的高度与Lable不匹配的解决办法.自定义类继承NSTextAttachment,一个快速的方法使其高度相等,** 修改它的y值,为-高度*0.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. **