NSPredicate(谓词),是一个Foundation类,可以使用它指定数据被获取或者过滤的方式。它的查询语言就像SQL的WHERE和正则表达式的交叉类似,来定义一个集合被搜寻的逻辑条件。
在集合中使用NSPredicate
Foundation中提供了使用NSPredicate
来过滤NSArray/NSMutableArray&NSSet/NSMutableSet
的方法。
不可变的集合,NSArray&NSSet
,有可以通过评估接收到的predicate来返回一个不可变集合的方法filteredArrayUsingPredicate:
和filteredSetUsingPredicate:。
可变集合,NSMutableArray&NSMutableSet
,可以使用方法filterUsingPredicate:
,它可以通过运行接收到的谓词来移除评估结果为FALSE的对象。
NSArray *array = @[@"jim",@"cook",@"jobs",@"sdevm"];
NSPredicate *preLength = [NSPredicate predicateWithFormat:@"length > 3"];
NSLog(@"array = %@",array);
NSLog(@"array precidate=%@",[array filteredArrayUsingPredicate:preLength]);
NSMutableArray *muArray = [NSMutableArray arrayWithObjects:@"jim",@"cook",@"jobs",@"sdevm", nil];
[muArray filterUsingPredicate:preLength];
NSLog(@"muArray=%@",muArray);
常用筛选方法:
利用成员实例的方法 ,类似上面的方法。
NSArray *array2 = @[@"2",@"3",@"4",@"5"];
NSPredicate *preIntergeris3 = [NSPredicate predicateWithFormat:@"integerValue >= 3"];
NSPredicate *preIntergeris3_2 = [NSPredicate predicateWithFormat:@"integerValue >= %@",@3];
NSLog(@"array2 with preIntergeris3 = %@",[array2 filteredArrayUsingPredicate:preIntergeris3]);
扩展到对象类:
@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property NSNumber *age;
@end
@implementation Person
- (NSString *)description {
return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
@end
NSArray *firstNames = @[ @"Alice", @"Bob", @"Charlie", @"Quentin" ];
NSArray *lastNames = @[ @"Smith", @"Jones", @"Smith", @"Alberts" ];
NSArray *ages = @[ @24, @27, @33, @31 ];
NSMutableArray *people = [NSMutableArray array];
[firstNames enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
Person *person = [[Person alloc]init];
person.firstName = [firstNames objectAtIndex:idx];
person.lastName = [lastNames objectAtIndex:idx];
person.age= [ages objectAtIndex:idx];
[people addObject:person];
}];
NSPredicate *precidate1 = [NSPredicate predicateWithFormat:@"firstName = 'Bob'"];
NSPredicate *precidate2 = [NSPredicate predicateWithFormat:@"lastName = %@", @"Smith"];
NSPredicate *precidate3 = [NSPredicate predicateWithFormat:@"age >= 30"];
// ["Bob Jones"]
NSLog(@"Bobs: %@", [people filteredArrayUsingPredicate:precidate1]);
// ["Alice Smith", "Charlie Smith"]
NSLog(@"Smiths: %@", [people filteredArrayUsingPredicate:precidate2]);
// ["Charlie Smith", "Quentin Alberts"]
NSLog(@"30's: %@", [people filteredArrayUsingPredicate:precidate3]);
三个Predicate的含义是:
对数组中的成员对象Person对象,使用[Person firstName] (firstName的get方法),返回=Bob的对象 。
对数组中的成员对象Person对象,使用[Person lastName] (firstName的get方法),返回=Smith的对象 。
对数组中的成员对象Person对象,使用[Person age] (firstName的get方法),返回>=30的对象 。
这里针对NSString
的操作,使用的是=
号,这里好像和==
效果是一样的。 来判断字符串是否相同。那么如何判断字符串包含另外一个字符串呢?可以在NSPredicate中使用CONTAINS(大小写都可以)
来表示包含关系。
当判断的时候需要忽略大小写可以使用
[cd] >[c]
,忽略重音符使用[cd] >[d]
,即不区分大小写,写不区分发音符号则使用[cd]
NSPredicate *precidateContainsali = [NSPredicate predicateWithFormat:@"firstName contains[cd] %@",@"ali"];
// ["Alice Smith"]
NSLog(@"contains ali = %@",[people filteredArrayUsingPredicate:precidateContainsali]);
涉及到更复杂的查询语句,比如说判断字符串以某个字符串开头,或者结尾,通配符的使用。
BEGINSWITH(以某个字符串开头,begins with) && ENDSWITH(ends with 以某个字符串结尾)
NSPredicate *precidateBeginsWith = [NSPredicate predicateWithFormat:@"firstName beginswith[cd] %@",@"a"];
NSLog(@"Beginswith ali = %@",[people filteredArrayUsingPredicate:precidateBeginsWith]);
NSPredicate *precidateEndWith = [NSPredicate predicateWithFormat:@"firstName endswith[cd] %@",@"e"];
NSLog(@"EndWith ali = %@",[people filteredArrayUsingPredicate:precidateEndWith]);
通配符LIKE *
代表一个或者多个或者是空字符, ?
代表一个字符 。
NSPredicate *predicateLike = [NSPredicate predicateWithFormat:@"firstName Like[cd] %@",@"??I*"];
//["Alice Smith"]
NSLog(@"Like ??i = %@",[people filteredArrayUsingPredicate:predicateLike]);
关系运算 IN ,BETWEEN ,AND ,OR,NOT IN
- IN判断是否在之中**
- OR(或,可以用||代替),OR可以判断不同的属性,
- BETWEEN(之间),通常用来判断NSNumber对象。
- AND(且),可以使用&&代替
- NOT(非,可以用!代替)
NSPredicate *inPredicate = [NSPredicate predicateWithFormat:@"firstName in %@",@[@"Alice",@"Sgslg"]];
//["Alice Smith"]
NSLog(@"inpredicate = %@",[people filteredArrayUsingPredicate:inPredicate]);
NSPredicate *orPredicate = [NSPredicate predicateWithFormat:@"firstName == %@ OR firstName == %@",@"Alice",@"Aharlie"];
//["Alice Smith"],["Aharlie Smith"]
NSLog(@"inpredicate = %@",[people filteredArrayUsingPredicate:orPredicate]);
NSPredicate *orPredicate2 = [NSPredicate predicateWithFormat:@"firstName == %@ OR lastName == %@",@"Alice",@"Jones"];
//["Alice Smith"],["Bob Jones"]
NSLog(@"inpredicate = %@",[people filteredArrayUsingPredicate:orPredicate2]);
NOT最常用的用法是从一个数组中剔除另外一个数组的数据,这个可以使用一个双层循环,但是非常麻烦。但是用NSPredicate 加NOT运算符就非常简单了。 如代码:
NSArray *arrayFilter = @[@"abc1", @"abc2"];
NSArray *arrayContent = @[@"a1", @"abc1", @"abc4", @"abc2"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@" self in %@",arrayFilter];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"NOT(self in %@)",arrayFilter];
//[" abc1"],["abc2"]
NSLog(@"predicate1= %@",[arrayContent filteredArrayUsingPredicate:predicate]);
//[" a1"],["abc4"]
NSLog(@"predicate2= %@",[arrayContent filteredArrayUsingPredicate:predicate2]);
##(NSPredicate)predicateWithBlock:(BOOL (^)(id evaluatedObject, NSDictionary bindings))block
事实上,因为block可以封装任意的计算,所以有一个查询类是无法以NSPredicate格式字符串形式来表达的(比如对运行时被动态计算的值的评估)。而且当同一件事情可以用NSExpression结合自定义选择器来完成时,block为完成工作提供了一个方便的接口。
NSPredicate *blockPredicate = [NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
return [[evaluatedObject lastName] length] <= 5;
}];
NSLog(@"Short Names = %@",[people filteredArrayUsingPredicate:blockPredicate]);
重要提示:由predicateWithBlock:生成的NSPredicate不能用于由SQLite存储库支持的Core Data数据的提取要求。
NSCompoundPredicate
我们见过与&或被用在谓词格式字符串中以创建复合谓词。然而,我们也可以用NSCompoundPredicate来完成同样的工作。
下面的谓词是相等的:
NSPredicate *orPredicate = [NSPredicate predicateWithFormat:@"firstName == %@ OR firstName == %@",@"Alice",@"Aharlie"];
//["Alice Smith"],["Aharlie Smith"]
NSLog(@"inpredicate = %@",[people filteredArrayUsingPredicate:orPredicate]);
NSCompoundPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[[NSPredicate predicateWithFormat:@"firstName == %@",@"Alice"],[NSPredicate predicateWithFormat:@"firstName == %@",@"Aharlie"]]];
NSLog(@"compoundPredicate = %@",[people filteredArrayUsingPredicate:compoundPredicate]);
匹配用法
NSPredicate 不仅可以用于筛选,还可以用于判断是否匹配,直接返回是否符合。
方法: - (BOOL)evaluateWithObject:(id)object;
使用方法:
Test *test1 = [[Test alloc]init];
test1.name = @"absr";
test1.code = @1;
NSPredicate *pres = [NSPredicate predicateWithFormat:@"code == %@", @2];
BOOL match = [pres evaluateWithObject:test1];
比较常用的还是配合正则表达式,列举几个常用的正则表达式:
1.是否以a开头以e结尾。
NSString *string=@"assdbfe";
NSString *targetString=@"^a.+e$";
NSPredicate *pres = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", targetString];
BOOL match = [pres evaluateWithObject:string];
2.是否是邮箱
NSString *strRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{1,5}";
3、是否是手机号:(包含了181,1700,1709,1705字段)
+ (BOOL)isMobileNumber:(NSString *)mobileNum
{
/**
* 中国移动:China Mobile
*
* 134[0-8],135,136,137,138,139,147,150,151,157,158,159,182,183,187,188,1705
*
*/
NSString * CM = @"^1((34[0-8]|(3[5-9]|5[017-9]|8[2378])|47\\d)|705)\\d{7}$";
/**
* 中国联通:China Unicom
*
* 130,131,132,152,155,156,185,186,1709
*
*/
NSString * CU = @"^1((3[0-2]|5[256]|8[56])[0-9]|709)\\d{7}$";
/**
* 中国电信:China Telecom
*
* 133,1349,153,180,189,181,177,1700
*
*/
NSString * CT = @"^1((33|53|77|8[019])[0-9]|349|700)\\d{7}$";
NSPredicate *regextestcm = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CM];
NSPredicate *regextestcu = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CU];
NSPredicate *regextestct = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CT];
if (
([regextestcm evaluateWithObject:mobileNum] == YES)
|| ([regextestcu evaluateWithObject:mobileNum] == YES)
|| ([regextestct evaluateWithObject:mobileNum] == YES)
){
return YES;
}
else{
return NO;
}
}
###谓词语法:
替换: %@是对值为字符串,数字或者日期的对象的替换值,
%K是key path的替换值。
NSPredicate *Kpredicate = [NSPredicate predicateWithFormat:@"%@= %@",@"age",@33];
//output Kpredicate : "age" == 33
NSLog(@"Kpredicate : %@",Kpredicate);
NSPredicate *Kpredicate2 = [NSPredicate predicateWithFormat:@"%K= %@",@"age",@33];
//output: Kpredicate : age == 33
NSLog(@"Kpredicate : %@",Kpredicate2);
// ["Aharlie Smith"]
NSLog(@"Age 33: %@", [people filteredArrayUsingPredicate:Kpredicate2]);