zoukankan      html  css  js  c++  java
  • iOS之谓词(NSPredicate)(正则表达式和UIBarController)

    本文转发至:https://segmentfault.com/a/1190000000623005

    NSPredicate,这个类和我上一篇博文中提到的valueForKeyPath一样很强大。它的使用主要集中在两个方法中

    NSArray

    - (NSArray *)filteredArrayUsingPredicate:(NSPredicate *)predicate;
    

    NSMutableArray

    - (void)filterUsingPredicate:(NSPredicate *)predicate;
    

    还有NSSetNSMutableSet也可以用这个类筛选。

    下面我就来一一介绍这个类的用法,相信大家看完后会和我一样认为这个类真的很强大。

    筛选用法

    • 利用成员实例方法
      筛选出长度大于3的字符串
        NSArray *array = @[@"jim", @"cook", @"jobs", @"sdevm"];
        NSPredicate *pre = [NSPredicate predicateWithFormat:@"length > 3"];
        NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);
    

    打印

    (
        cook,
        jobs,
        sdevm
    )
    

    lenght就是对数组成员执行[xxxx lenght]然后判断返回的NSUInteger值是否大于3。扩展到NSString其他方法比如integerValue

    NSArray *array = @[@"2", @"3", @"4", @"5"];
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"integerValue >= %@", @3];
    NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);
    
    

    如果我不想用任何实例方法,想筛选成员本身应该怎么做呢。这时候就可以用self来代替

    NSPredicate *pre = [NSPredicate predicateWithFormat:@"self CONTAINS %@", @3];
    

    CONTAINS用法后面会讲到

    再扩展到模型

    Test.h

    @interface Test : NSObject
    
    @property (nonatomic, strong) NSString *name;
    @property (nonatomic, strong) NSNumber *code;
    
    @end
    
    
        Test *test1 = [[Test alloc]init];
        test1.name = @"西湖";
        test1.code = @1;
    
        Test *test2 = [[Test alloc]init];
        test2.name = @"西溪湿地";
        test2.code = @2;
    
        Test *test3 = [[Test alloc]init];
        test3.name = @"灵隐寺";
        test3.code = @3;
    
        NSArray *array = @[test1, test2, test3];
        NSPredicate *pre = [NSPredicate predicateWithFormat:@"code >= %@", @2];
        NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);
    

    筛选出数组成员[test code]方法(code属性的get方法)返回值>=2的成员。这里的比较运算符同样也可以使用==!=<=<

    其实==不仅可以用来比较NSNumber对象,还可以用来判断NSString对象是否相同。

    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name == %@", @"西湖"];
    

    筛选出name是"西湖"的对象数组。

    • ###NSString对象的操作
      前面提到==比较运算符可以起到- (BOOL)isEqualToString:(NSString *)aString;方法的效果,来判断字符串是否相同。那么字符串中包含某个字符串应该如何判断呢,在NSPredicate中可以用CONTAINS(大小写都可以)来表示包含关系。
     NSPredicate *pre = [NSPredicate predicateWithFormat:@"name CONTAINS %@", @"湖"];
    

    当判断的时候需要忽略大小写可以使用[cd]

    [c] 忽略大小写

    [d] 忽略重音符号

    [cd]既不区分大小写,也不区分发音符号。

    使用:

    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@", @"abc"];
    

    再涉及到一些更复杂的查询语句,比如判断字符串以某个字符串开头或者结尾,通配符的使用。

    BEGINSWITH(已某个字符串开头, begins with)

        NSString *targetString = @"h";
        NSPredicate *pre = [NSPredicate predicateWithFormat:@"name BEGINSWITH %@",targetString];
    

    ENDSWITH(已某个字符串结尾, ends with)

        NSString *targetString = @"ing";
        NSPredicate *pre = [NSPredicate predicateWithFormat:@"name ENDSWITH %@",targetString];
    

    通配符 LIKE

    *代表一个或者多个或者是空

    ?代表一个字符

    Test *test1 = [[Test alloc]init];
    test1.name = @"absr";
    test1.code = @1;
    
    Test *test2 = [[Test alloc]init];
    test2.name = @"asb";
    test2.code = @2;
    
    Test *test3 = [[Test alloc]init];
    test3.name = @"raskj";
    test3.code = @3;
    
    NSArray *array = @[test1, test2, test3];
    
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name LIKE %@", @"?b*"];
    NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);
    

    结果是只有test1符合,like也可以接受[cd]

    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name LIKE[cd] %@", @"?b*"];
    

    关系运算,包括了INBETWEENANDORNOT

    IN(之中)

    NSPredicate *pre = [NSPredicate predicateWithFormat:@"code IN %@", @[@1, @3]];
    

    判断code是否@1或者是@2,也就是是否在数组中。

    OR(或,可以用||代替)

    OR可以用来代替IN达到同样的效果,但是OR更灵活。

    NSPredicate *pre = [NSPredicate predicateWithFormat:@"code == %@ OR code == %@ ", @1, @3];
    

    效果和IN一样,但是OR可以判断不只一个属性

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"code == %@ OR name == %@ ", @1, @"asb"];
    

    BETWEEN(之间)

    通常用于判断NSNumber对象

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"code BETWEEN {1, 3}"];
    

    判断code是否>=1且<=3

    AND(且,可以用&&代替)

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"code >= %@ AND code <=%@", @1, @3];
    

    NOT(非,可以用!代替)

    NOT最常见的用法就是从一个数组中剔除另外一个数组的数据,可能有点绕,举个例子就很明朗了。

        NSArray *arrayFilter = @[@"abc1", @"abc2"];
        NSArray *arrayContent = @[@"a1", @"abc1", @"abc4", @"abc2"];
        NSPredicate *thePredicate = [NSPredicate predicateWithFormat:@"NOT (SELF in %@)", arrayFilter];
        NSLog(@"%@",[arrayContent filteredArrayUsingPredicate:thePredicate]);
    

    打印

    (
        a1,
        abc4
    )
    

    比起循环比较再加到新数组中,简单的不止一两点。

    前面提到的都是用+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;方法创建,还有另一种常用的方法:+ (NSPredicate*)predicateWithBlock:(BOOL (^)(id evaluatedObject, NSDictionary *bindings))block,用Block形式创建

    NSPredicate *pre = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
        Test *test = (Test *)evaluatedObject;
        if (test.code.integerValue > 2) {
            return YES;
        }
        else{
            return NO;
        }
    }];
    

    参数evaluatedObject表示数组成员,block必须返回YES或者NO,分别表示匹配还是不匹配。请忽略bindings参数,具体作用我也没搞清楚。

    多重筛选

    如果需要匹配数个属性的筛选,用AND或者OR来串联显然有点麻烦,NSCompoundPredicate类可以满足我们的需求,它可以将多个NSPredicate对象的组合,组合方式可以是AND或者OR

        NSPredicate *pre1 = [NSPredicate predicateWithFormat:@"code >= %@", @3];
        NSPredicate *pre2 = [NSPredicate predicateWithFormat:@"code <= %@", @2];
    
        //以AND形式组合
        NSPredicate *pre = [NSCompoundPredicate andPredicateWithSubpredicates:@[pre1,pre2]];
        //以OR形式组合
        NSPredicate *pre = [NSCompoundPredicate orPredicateWithSubpredicates:@[pre1, pre2]];
    

    匹配用法

    其实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];
    

    当然最常用的还是配合配合正则表达式,列举几个常用的正则

    是否以a开头以e结尾

        NSString *string=@"assdbfe";
        NSString *targetString=@"^a.+e$";
        NSPredicate *pres = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", targetString];
        BOOL match = [pres evaluateWithObject:string];
    
    

    是否是邮箱

    NSString *strRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{1,5}"; 
    

    是否是手机号

    NSString *strRegex = @"[0-9]{1,20}";  
    

    不得不说,在利用+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;方法创建的NSPredicate对象的时候有个坑。

    在某些情况下,类似于上面例子中的code字符串不是很明确,创建的时候就会这样使用

    Test *test1 = [[Test alloc]init];
    test1.name = @"absr";
    test1.code = @1;
    
    Test *test2 = [[Test alloc]init];
    test2.name = @"asb";
    test2.code = @2;
    
    Test *test3 = [[Test alloc]init];
    test3.name = @"raskj";
    test3.code = @3;
    
    NSArray *array = @[test1, test2, test3];
    
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"%@ == %@", @"code", @2];
    NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);
    

    注意NSPredicate对象的初始化方式。运行这块代码你会发现test2对象没有被查询出来。打印pre发现"code" == 2,这说明查找的是"code"方法的返回值,这显然行不通。

    如果查询的是属性,比如code是Test类的属性,那么利用下面的创建方式

    NSPredicate *pre = [NSPredicate predicateWithFormat:@"%K == %@", @"code", @2];
    

    就不会被坑

    注意:%KK必须是大写。

    最后

    NSPredicate几乎可以满足所有形式的查询,配合Core Data的数据库查询当然不在话下。NSPredicate用法不只这些,有兴趣的同学可以看下nshipster网站的这篇博文,里面提到了一些我没有涉及到的用法。

  • 相关阅读:
    1093 Count PAT's(25 分)
    1089 Insert or Merge(25 分)
    1088 Rational Arithmetic(20 分)
    1081 Rational Sum(20 分)
    1069 The Black Hole of Numbers(20 分)
    1059 Prime Factors(25 分)
    1050 String Subtraction (20)
    根据生日计算员工年龄
    动态获取当前日期和时间
    对计数结果进行4舍5入
  • 原文地址:https://www.cnblogs.com/liumu/p/5380476.html
Copyright © 2011-2022 走看看