有时我们需要在一大段长文本中过滤出我们需要的字段,或者检验该文本是否符合要求(该文本是否是邮箱,链接,电话号码或身份证),这时候就需要用到正则表达式了,当然我们也可以使用 NSPredicate,这不重要,重要的是表达式对于刷选和逻辑判断来说是十分方便的。
文章脉络
Predicate(谓语)的意思。NSPredicate类是用来定义逻辑条件约束的获取或内存中的过滤搜索。原理和用法都类似于SQL中的where,作用相当于数据库的过滤取 NSPredicate真的是Cocoa的优势之一。其他语言的第三方库根本没法和他比。对于我们这些应用和框架开发者来说,有它作为标准组件使得我们在处理数据时有了很大的优势。
NSPredicate语法:
=、==:判断两个表达式是否相等,在谓词中=和==是相同的意思都是判断,而没有赋值这一说
NSNumber *testNumber = @123;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF = 123"];
if ([predicate evaluateWithObject:testNumber]) {
NSLog(@"testString:%@", testNumber);
}
我们可以看到输出的内容为:
2016-01-07 11:12:27.281 PredicteDemo[4130:80412] testString:123
=,=>:判断左边表达式的值是否大于或等于右边表达式的值 <=,=<:判断右边表达式的值是否小于或等于右边表达式的值 :判断左边表达式的值是否大于右边表达式的值 <:判断左边表达式的值是否小于右边表达式的值 !=、<>:判断两个表达式是否不相等 BETWEEN:BETWEEN表达式必须满足表达式 BETWEEN {下限,上限}的格式,要求该表达式必须大于或等于下限,并小于或等于上限 NSNumber *testNumber = @123; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF BETWEEN {100, 200}"]; if ([predicate evaluateWithObject:testNumber]) { NSLog(@"testString:%@", testNumber); } else { NSLog(@"不符合条件");
}
输出结果为:
2016-01-07 11:20:39.921 PredicteDemo[4366:85408] testString:123
AND、&&:逻辑与,要求两个表达式的值都为YES时,结果才为YES。 NSArray *testArray = @[@1, @2, @3, @4, @5, @6]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF > 2 && SELF < 5"]; NSArray *filterArray = [testArray filteredArrayUsingPredicate:predicate]; NSLog(@"filterArray:%@", filterArray); 输出结果为: 2016-01-07 11:27:01.885 PredicteDemo[4531:89537] filterArray:( 3, 4 ) OR、||:逻辑或,要求其中一个表达式为YES时,结果就是YES NOT、 !:逻辑非,对原有的表达式取反
BEGINSWITH:检查某个字符串是否以指定的字符串开头(如判断字符串是否以a开头:BEGINSWITH 'a') ENDSWITH:检查某个字符串是否以指定的字符串结尾 CONTAINS:检查某个字符串是否包含指定的字符串 LIKE:检查某个字符串是否匹配指定的字符串模板。其之后可以跟?代表一个字符和代表任意多个字符两个通配符。比如"name LIKE 'ac'",这表示name的值中包含ac则返回YES;"name LIKE '?ac'",表示name的第2、3个字符为ac时返回YES。
MATCHES:检查某个字符串是否匹配指定的正则表达式。虽然正则表达式的执行效率是最低的,但其功能是最强大的,也是我们最常用的。所以NSPredicate也可以结合正则表达式语句来使用。
注:字符串比较都是区分大小写和重音符号的。如:café和cafe是不一样的,Cafe和cafe也是不一样的。如果希望字符串比较运算不区分大小写和重音符号,请在这些运算符后使用[c],[d]选项。其中[c]是不区分大小写,[d]是不区分重音符号,其写在字符串比较运算符之后,比如:name LIKE[cd] 'cafe',那么不论name是cafe、Cafe还是café上面的表达式都会返回YES。
ANY、SOME:集合中任意一个元素满足条件,就返回YES。 ALL:集合中所有元素都满足条件,才返回YES。 NONE:集合中没有任何元素满足条件就返回YES。如:NONE person.age < 18,表示person集合中所有元素的age>=18时,才返回YES。 IN:等价于SQL语句中的IN运算符,只有当左边表达式或值出现在右边的集合中才会返回YES。我们通过一个例子来看一下 NSArray *filterArray = @[@"ab", @"abc"]; NSArray *array = @[@"a", @"ab", @"abc", @"abcd"]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", filterArray]; NSLog(@"%@", [array filteredArrayUsingPredicate:predicate]); 代码的作用是将array中和filterArray中相同的元素去除,输出为: 2016-01-07 13:17:43.669 PredicteDemo[6701:136206] ( a, abcd ) array[index]:返回array数组中index索引处的元素 array[FIRST]:返回array数组中第一个元素 array[LAST]:返回array数组中最后一个元素 array[SIZE]:返回array数组中元素的个数
在谓词表达式中可以使用如下直接量 FALSE、NO:代表逻辑假 TRUE、YES:代表逻辑真 NULL、NIL:代表空值 SELF:代表正在被判断的对象自身 "string"或'string':代表字符串 数组:和c中的写法相同,如:{'one', 'two', 'three'}。 数值:包括证书、小数和科学计数法表示的形式 十六进制数:0x开头的数字 八进制:0o开头的数字 二进制:0b开头的数字
谓词的用法
常用 NSPredicate 实例
RegularExpression 的汉语意思就是正则表达式,所以 NSRegularExpression 才是iOS中的正则表达式, 不熟悉的人会错误地以为NSPredicate 是正则表达式。下面介绍一下 NSRegularExpression
NSRegularExpression 位于 Foundation 框架中,主要作用相当与检索条件判断,但是其强大方便的功能是以晦涩的语法为牺牲的。如果你想仔细研究的话,可以看这俩篇文章:语法列表& 入门教程 如果你看哭了,不要找我,/笑哭
正则表达式最主要的作用是查找刷选、或者替换,当然也可以用来做判断。numberOfMatchesInString 为0就是没有一个匹配的目标,也就是 NO 。
NSRegularExpression 的相关方法
# 初始化方法
+ (nullable NSRegularExpression *)regularExpressionWithPattern:(NSString *)pattern options:(NSRegularExpressionOptions)options error:(NSError **)error;
- (nullable instancetype)initWithPattern:(NSString *)pattern options:(NSRegularExpressionOptions)options error:(NSError **)error NS_DESIGNATED_INITIALIZER;
# 操作方法
返回所有匹配结果的集合(适合,从一段字符串中提取我们想要匹配的所有数据)
- (NSArray<NSTextCheckingResult *> *)matchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
返回正确匹配的个数(通过等于0,来验证邮箱,电话什么的,代替NSPredicate)
- (NSUInteger)numberOfMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
返回第一个匹配的结果。注意,匹配的结果保存在 NSTextCheckingResult 类型中
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
返回第一个正确匹配结果字符串的NSRange
- (NSRange)rangeOfFirstMatchInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
block方法 枚举每个符合约定的字段,通过block对其进行操作
- (void)enumerateMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range usingBlock:(void (^)(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop))block;
*/
# NSRegularExpression类中提供了方法来实现用新的字段来替换原文中符合规则的字段。
用新字段替换原文本中的对应字段,并返回操作后的NSString
- (NSString *)stringByReplacingMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range withTemplate:(NSString *)templ;
用新字段替换原文本中的对应字段,并返回操作次数(替换字段的个数)
- (NSUInteger)replaceMatchesInString:(NSMutableString *)string options:(NSMatchingOptions)options range:(NSRange)range withTemplate:(NSString *)templ;
# NSRegularExpressionOptions;
NSRegularExpressionCaseInsensitive = 1 << 0, // 不区分大小写的
NSRegularExpressionAllowCommentsAndWhitespace = 1 << 1, // 忽略空格和# -
NSRegularExpressionIgnoreMetacharacters = 1 << 2, // 整体化
NSRegularExpressionDotMatchesLineSeparators = 1 << 3, // 匹配任何字符,包括行分隔符
NSRegularExpressionAnchorsMatchLines = 1 << 4, // 允许^和$在匹配的开始和结束行
NSRegularExpressionUseUnixLineSeparators = 1 << 5, // (查找范围为整个的话无效)
NSRegularExpressionUseUnicodeWordBoundaries = 1 << 6 // (查找范围为整个的话无效)
};
# NSTextCheckingResult 这是一个文本搜索结果对象里面包含了 Range 属性 和一个文本搜索类型 的属性,
我们只需要使用 Range 属性 即可.
[@"原文本" substringWithRange:range]] 即可获取匹配到的内容
Paste_Image.png
示例
# 测试字符串,把里面的电话号码解析出来
NSString *urlString = @"哈哈哈哈呵呵呵s15279107723在这里啊啊啊啊s15279107716";
NSError *error = NULL;
// 根据匹配条件,创建了一个正则表达式(类方法,实例方法类似)
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\d{3}-\\d{8}|\\d{3}-\\d{7}|\\d{4}-\\d{8}|\\d{4}-\\d{7}|1+[358]+\\d{9}|\\d{8}|\\d{7}" options:NSRegularExpressionCaseInsensitive error:&error];
if (regex != nil) {
NSTextCheckingResult *firstMatch = [regex firstMatchInString:urlString
options:0
range:NSMakeRange(0, [urlString length])];
if (firstMatch) {
NSRange resultRange = [firstMatch rangeAtIndex:0];
//从urlString中截取数据
NSString *result = [urlString substringWithRange:resultRange];
NSLog(@"result = %@",result);
}
NSUInteger number = [regex numberOfMatchesInString:urlString
options:0
range:NSMakeRange(0, [urlString length])];
NSLog(@"number = %ld",number);
[regex enumerateMatchesInString:urlString options:0 range:NSMakeRange(0, [urlString length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOLBOOL *stop) {
NSLog(@"---%@",NSStringFromRange([result range]));
if (flags != NSMatchingInternalError) {
NSRange firstHalfRange = [result rangeAtIndex:0];
if (firstHalfRange.length > 0) {
NSString *resultString1 = [urlString substringWithRange:firstHalfRange];
NSLog(@"result1 = %@",resultString1);
}
}
*stop = YES;
}];
}
需要注意的地方
有些正则表达式 在转化成字符串时就有出编译警告,对元字符需要转译,比如下面这个验证邮箱的正则表达式:
\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
NSString *regex = @"\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
常用正则表达式
(1)^和$属于特殊符号,前者表示匹配字符串的开头,后者表示匹配字符串的结尾。 (2)得出.符号表示任一字符(除换行符之外)。 (3)还有\d用来表示任意的单个数字,\w表示任意一个字母或数字或者直接使用0-9的任意数字表示具体数字。而特殊符号?表示前一个字符为0或者1个。 (4)表达式的字符分为两类:值表达和修饰表达。所谓值表达就是说这个符号表示了某个值,就像\d表示数字,.表示任意非换行符字符。修饰表达用来修饰值达成某种条件,比如{2}表示前面一个值重复两次,*表示前一个值重复0次或者更多次。 结合例子解释正则表达式
单语法/字符说明表 值表达
语法 | 意义 |
---|---|
. | 匹配除换行符外的任意字符 |
\w | 匹配字母或者数字的字符 |
\W | 匹配任意不是字母或数字的字符 |
\s | 匹配任意的空白符(空格、制表符、换行符) |
\S | 匹配任意不是空白符的字符 |
\d | 匹配任意数字 |
\D | 匹配任意非数字的字符 |
\b | 匹配单词的结尾或者开头的字符 |
\B | 匹配任意不是单词结尾或开头的字符 |
[^x] | 匹配任意非x的字符。如[^[a-z]]匹配非小写字母的任意字符 |
^ | 匹配字符串的开头 |
$ | 匹配字符串的结尾 |
修饰表达
语法 | 意义 |
---|---|
* | 匹配重复任意次数 |
+ | 匹配重复一次以上的次数 |
? | 匹配一次或零次 |
{n} | 匹配重复n次 |
{n,} | 匹配重复n次或n次以上 |
{n,m} | 匹配重复最少n次最多m次 |
除了这些常见的,想了解更多可以查阅文章上面推荐的一篇语法文章。
以下是摘自一位作者的总结,感觉很不错,就拿来用了,出自此处
一、校验数字的表达式
二、校验字符的表达式
三、特殊需求表达式
这算是一篇科普类文章,对自己来说也是一个笔记,以后用到相关的知识可以来此查看,中间引用了其他作者的作品,再次表示感谢,同时也文中也有指明出处。后续会持续更新新的使用方法。(未完 待续........)