前言
在開發(fā)中秩霍,我們經(jīng)常會遇到一些需要宵呛,讓我們從集合中查找某個(gè)值单匣,從集合中過濾想要的內(nèi)容等等,因而我們就需要遍歷集合宝穗,加條件判斷户秤,然后獲取符合條件的值。而關(guān)于集合的遍歷是所有軟件開發(fā)從業(yè)人員經(jīng)常打交道的一些事情逮矛。
把范圍縮小到iOS開發(fā)中鸡号,關(guān)于集合地遍歷的方法就有好多種,人們一直在討論和爭辯须鼎,想尋找出一種最快最有效的方法鲸伴,是用for循環(huán),還是block晋控,是用并發(fā)操作汞窗,還是順序操作,等等赡译。甚至有人不惜使用大數(shù)據(jù)量來測試各種遍歷方式的效率以及精確度仲吏。
NSPredicate
一種類似于SQL語句來過濾集合內(nèi)容的方式從而避免了自己進(jìn)行集合遍歷的方法,就是NSPredicate。蘋果在Cocoa touch框架給我們提供了NSPredicate這個(gè)類裹唆,封裝了一些讓我們可以直接對集合設(shè)置過濾條件的方法誓斥,而至于蘋果是如何在SDK中進(jìn)行數(shù)據(jù)查找地,我們并不需要關(guān)心许帐,因?yàn)槲蚁嘈潘龅囊欢ū任覀兒冕场W(xué)過SQL語法的人,使用NSPredicate會十分容易舞吭。下面詳細(xì)的講述NSPredicate的語法規(guī)則。
簡單說明
NSPredict 謂詞可以通過定義一個(gè)邏輯條件析珊,來搜索查詢羡鸥、過濾信息
NSPredict主要包含三個(gè)子類:NSComparisonPredicate、NSCompoundPredicate忠寻、NSExpression
NSPredict 表達(dá)式
在介紹NSPredict的使用之前惧浴,我們必須先要了解如何正確的書寫謂詞表達(dá)式
比較運(yùn)算符
= 、 == (判斷兩個(gè)表達(dá)式是否相等)
=>奕剃、>= (左側(cè)表達(dá)式是否大于或等于右側(cè)表達(dá)式)
<= 衷旅、 =< (左側(cè)表達(dá)式是否小于或等于右側(cè)表達(dá)式)
< 、 > (左側(cè)表達(dá)式是否大于纵朋、小于右側(cè)表達(dá)式)
柿顶!= 、<> (兩個(gè)表達(dá)式是否不相等)
BETWEEN (”表達(dá)式 BEYWEEN {最小值操软,最大值}“ 嘁锯,表達(dá)式必須大于等于最小值或小于等于最大值)
邏輯運(yùn)算符
AND、&& (兩個(gè)表達(dá)式都為真是聂薪,結(jié)果為真家乘;有假則結(jié)果為假)
OR、|| (兩個(gè)表達(dá)式有一個(gè)結(jié)果為真藏澳,結(jié)果為真仁锯;同為假,則結(jié)果為假)
NOT 翔悠、业崖! ( 表達(dá)式結(jié)果取反)
字符串比較運(yùn)算符
BEGINSWITH (字符串是否以某一子字符串開頭)
ENDSWITH (字符串是否以某一子字符串結(jié)尾)
CONTAINS (字符串是否包含某一子字符串)
LIKE (字符串是否匹配指定的字符串模板)
title LIKE *abc? :title現(xiàn)有任意多的字符串,結(jié)尾必須為abc+任意一個(gè)字符
MATCHES (字符串是否匹配指定的正則表達(dá)式蓄愁;正則表達(dá)式功能強(qiáng)大腻要,但是執(zhí)行效率低。能用謂詞表達(dá)式的就不要用正則表達(dá)式)
注意:字符串比較運(yùn)算符默認(rèn)區(qū)分大小寫和重音符號
1.如果希望字符串比較運(yùn)算符不區(qū)分大小寫涝登,可以再運(yùn)算符后添加[c]
2.如果希望字符串比較運(yùn)算符不區(qū)分重音符號雄家,可以再運(yùn)算符后添加[d]
一般都是在運(yùn)算符后面添加[cd],代表不區(qū)分大小寫和重音符號
集合操作相關(guān)的運(yùn)算符
ANY 、SOME (集合中任意一個(gè)元素滿足條件,返回YES)
ALL (集合中多有元素滿足條件趟济,返回YES)
NONE (集合中任何元素不滿足條件乱投,返回YES)
IN (左邊的表達(dá)式(值) 在右邊的集合中存在,返回YES)
array[index] ( 返回?cái)?shù)組index索引處的元素)
array[FIRST] (返回?cái)?shù)組第一個(gè)元素)
array[LAST] ( 返回?cái)?shù)組最后一個(gè)元素)
array[SIZE] ( 返回?cái)?shù)組元素個(gè)數(shù))
謂詞表達(dá)式中的直接量
FALSE顷编、NO ( 邏輯假)
TRUE戚炫、YES ( 邏輯真)
NULL、NIL ( 空值)
SELF (被判斷的對象本身)
"text"('text') (字符串)
數(shù)組 (數(shù)組元素以英文逗號隔開)
數(shù)值直接量 (整數(shù)媳纬、小數(shù)双肤、科學(xué)技術(shù)法)
各進(jìn)制數(shù) (0x(十六進(jìn)制)、0o(八進(jìn)制)钮惠、0b(二進(jìn)制))
注意:謂詞表達(dá)式中" "與' '效果相同茅糜,但是“ ”與‘ ’應(yīng)該匹配
保留字:大寫單詞是保留字
MATCHES、CONTAINS素挽、BEGINSWITH蔑赘、ENDSWIHT、BETWEEN预明、NULL缩赛、NIL、SELF撰糠、AND酥馍、OR、IN阅酪、NOT物喷、ALL、ANY遮斥、SOME峦失、NONE、LIKE术吗、CASEINSENSITIVE尉辑、CI、TRUE较屿、YES隧魄、FALSE、NO隘蝎、FIRST购啄、LAST、SIZE嘱么、ANYKEY狮含、SUBQUERY、CAST、TRUEPREDICATE几迄、FALSEOREDICATE
謂詞NSPredict實(shí)際使用
(1)對NSArray進(jìn)行過濾
NSPredict 本質(zhì)上就是一個(gè)邏輯條件蔚龙,NSPredict 運(yùn)算的結(jié)果就是一個(gè)BOOL值
NSPredict 一個(gè)比較常用的功能就是對集合元素的過濾; 自動遍歷集合元素------>根據(jù)元素判斷 NSPredict 的結(jié)果------>結(jié)果為YES時(shí),集合元素保存
注意謂詞過濾不可變集合映胁,結(jié)果返回符合條件的新集合木羹;謂詞過濾可變集合,直接將集合中不符合條件的元素去掉
示例1:
NSArray * array = @[@"libai",@"dufu",@"sushi",@"dumu"];
NSPredicate * pred = [NSPredicate predicateWithFormat:@"SELF like %@",@"du*"];
NSArray * resultArr = [array filteredArrayUsingPredicate:pred];
NSLog(@"%@",resultArr);//輸出值:(
dufu,
dumu
)
NSSet * set = [NSSet setWithObjects:
[[CXHPerson alloc]initWithName:@"li si" Age:@"25"],
[[CXHPerson alloc]initWithName:@"zhang san" Age:@"20"],
[[CXHPerson alloc]initWithName:@"wang wu" Age:@"18"],nil
];
NSPredicate * pred3 = [NSPredicate predicateWithFormat:@"name CONTAINS 'ang'"];
NSSet * resultSet = [set filteredSetUsingPredicate:pred3];
for (CXHPerson * person in resultSet) {
NSLog(@"%@",person.name);
}
NSArray * array3 = @[[[CXHPerson alloc]initWithName:@"li si" Age:@"25"],
[[CXHPerson alloc]initWithName:@"zhang san" Age:@"20"],
[[CXHPerson alloc]initWithName:@"wang wu" Age:@"18"]];
NSArray * array4 = [array3 filteredArrayUsingPredicate:pred3];
for (CXHPerson * person in array4) {
NSLog(@"%@",person.name);
}
//輸出值:
zhang san
wang wu
示例2:
NSArray *array = [[NSArray alloc]initWithObjects:@"beijing",@"shanghai",@"guangzou",@"wuhan", nil];
NSString *string = @"ang";
NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF CONTAINS %@",string];
NSLog(@"%@",[array filteredArrayUsingPredicate:pred]);
(2)判斷字符串首字母是否為字母:
NSString *regex = @"[A-Za-z]+";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
if ([predicate evaluateWithObject:aString]) {
}
(3)字符串替換:
NSError* error = NULL;
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:@"(encoding=\"){FNXX==XXFN}+(\")"
options:0
error:&error];
NSString* sample = @"<xml encoding=\"abc\"></xml><xml encoding=\"def\"></xml><xml encoding=\"ttt\"></xml>";
NSLog(@"Start:%@",sample);
NSString* result = [regex stringByReplacingMatchesInString:sample
options:0
range:NSMakeRange(0, sample.length)
withTemplate:@"$1utf-8$2"];
NSLog(@"Result:%@", result);
(4)截取字符串如下:
//組裝一個(gè)字符串解孙,需要把里面的網(wǎng)址解析出來
NSString *urlString=@"<meta/><link/><title>1Q84 BOOK1</title></head><body>";
//NSRegularExpression類里面調(diào)用表達(dá)的方法需要傳遞一個(gè)NSError的參數(shù)坑填。下面定義一個(gè)
NSError *error;
//http+:[^\\s]* 這個(gè)表達(dá)式是檢測一個(gè)網(wǎng)址的。(?<=title\>).*(?=</title)截取html文章中的<title></title>中內(nèi)文字的正則表達(dá)式
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(?<=title\\>).*(?=</title)" options:0 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當(dāng)中截取數(shù)據(jù)
NSString *result=[urlString substringWithRange:resultRange];
//輸出結(jié)果
NSLog(@"->%@<-",result);
}
}
(5)判斷手機(jī)號碼弛姜,電話號碼函數(shù)
// 正則判斷手機(jī)號碼地址格式
- (BOOL)isMobileNumber:(NSString *)mobileNum
{
/**
* 手機(jī)號碼
* 移動:134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188
* 聯(lián)通:130,131,132,152,155,156,185,186
* 電信:133,1349,153,180,189
*/
NSString * MOBILE = @"^1(3[0-9]|5[0-35-9]|8[025-9])\\d{8}$";
/**
10 * 中國移動:China Mobile
11 * 134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188
12 */
NSString * CM = @"^1(34[0-8]|(3[5-9]|5[017-9]|8[278])\\d)\\d{7}$";
/**
15 * 中國聯(lián)通:China Unicom
16 * 130,131,132,152,155,156,185,186
17 */
NSString * CU = @"^1(3[0-2]|5[256]|8[56])\\d{8}$";
/**
20 * 中國電信:China Telecom
21 * 133,1349,153,180,189
22 */
NSString * CT = @"^1((33|53|8[09])[0-9]|349)\\d{7}$";
/**
25 * 大陸地區(qū)固話及小靈通
26 * 區(qū)號:010,020,021,022,023,024,025,027,028,029
27 * 號碼:七位或八位
28 */
// NSString * PHS = @"^0(10|2[0-5789]|\\d{3})\\d{7,8}$";
NSPredicate *regextestmobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", MOBILE];
NSPredicate *regextestcm = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CM];
NSPredicate *regextestcu = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CU];
NSPredicate *regextestct = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CT];
if (([regextestmobile evaluateWithObject:mobileNum] == YES) || ([regextestcm evaluateWithObject:mobileNum] == YES)|| ([regextestct evaluateWithObject:mobileNum] == YES) || ([regextestcu evaluateWithObject:mobileNum] == YES)) {
if([regextestcm evaluateWithObject:mobileNum] == YES) {
NSLog(@"China Mobile");
} else if([regextestct evaluateWithObject:mobileNum] == YES) {
NSLog(@"China Telecom");
} else if ([regextestcu evaluateWithObject:mobileNum] == YES) {
NSLog(@"China Unicom");
} else {
NSLog(@"Unknow");
}
return YES;
} else {
return NO;
}
}
(6)郵箱驗(yàn)證脐瑰、電話號碼驗(yàn)證:
//是否是有效的正則表達(dá)式
+(BOOL)isValidateRegularExpression:(NSString *)strDestination byExpression:(NSString *)strExpression {
NSPredicate *predicate = [NSPredicatepredicateWithFormat:@"SELF MATCHES %@", strExpression];
return [predicate evaluateWithObject:strDestination];
}
//驗(yàn)證email
+(BOOL)isValidateEmail:(NSString *)email {
NSString *strRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{1,5}";
BOOL rt = [CommonTools isValidateRegularExpression:email byExpression:strRegex];
return rt;
}
//驗(yàn)證電話號碼
+(BOOL)isValidateTelNumber:(NSString *)number {
NSString *strRegex = @"[0-9]{1,20}";
BOOL rt = [CommonTools isValidateRegularExpression:number byExpression:strRegex];
return rt;
}
(7)NSDate進(jìn)行篩選
//日期在十天之內(nèi):
NSDate *endDate = [[NSDate date] retain];
NSTimeInterval timeInterval= [endDate timeIntervalSinceReferenceDate];
timeInterval -=3600*24*10;
NSDate *beginDate = [[NSDate dateWithTimeIntervalSinceReferenceDate:timeInterval] retain];
//對coredata進(jìn)行篩選(假設(shè)有fetchRequest)
NSPredicate *predicate_date = [NSPredicate predicateWithFormat:@"date >= %@ AND date <= %@", beginDate,endDate];
[fetchRequest setPredicate:predicate_date];
//釋放retained的對象
[endDate release];
[beginDate release];
(8)NSPredict 的占位符參數(shù)
通過使用占位符,在謂詞表達(dá)式中使用變量
%K : 動態(tài)傳入屬性名
%@ : 動態(tài)設(shè)置屬性值
$SUBSTR : 一個(gè)動態(tài)變化的值娱据,可以通過它動態(tài)改變比較條件
//設(shè)置NSPredict 中的可變參數(shù),并計(jì)算結(jié)果
- (BOOL)evaluateWithObject:(nullable id)object substitutionVariables:(nullable NSDictionary<NSString *, id> *)bindings NS_AVAILABLE(10_5, 3_0); // single pass evaluation substituting variables from the bindings dictionary for any variable expressions encountered
//設(shè)置NSPredict 的可變參數(shù)盅惜,返回一個(gè)NSPredict 對象
- (instancetype)predicateWithSubstitutionVariables:(NSDictionary<NSString *, id> *)variables; // substitute constant values for variables
示例代碼
CXHPerson * person1 = [[CXHPerson alloc]initWithName:@"zhang san" Age:@"21"];
CXHPerson * person2 = [[CXHPerson alloc]initWithName:@"li si" Age:@"25"];
CXHPerson * person3 = [[CXHPerson alloc]initWithName:@"stark" Age:@"11"];
CXHPerson * person4 = [[CXHPerson alloc]initWithName:@"sunny" Age:@"30"];
NSArray * array2 = @[person1,person2,person3,person4];
NSString * name = @"age";
NSString * age = @"3";
NSPredicate * changePre1 = [NSPredicate predicateWithFormat:@"%K CONTAINS[cd] %@",name,age];
NSArray * newArray2 = [array2 filteredArrayUsingPredicate:changePre1];
for (CXHPerson * person in newArray2) {
NSLog(@"newArray2%@----%@",person.name,person.age);
}
//name中包含$SUBSTR的字串
NSPredicate * changePre2 = [NSPredicate predicateWithFormat:@"%K CONTAINS[cd] $SUBSTR",@"name"];
//指定$SUBSTR的值為sun
NSPredicate * newChangePre2 = [changePre2 predicateWithSubstitutionVariables:@{@"SUBSTR":@"sun"}];
NSArray * newArray3 = [array2 filteredArrayUsingPredicate:newChangePre2];
for (CXHPerson * person in newArray3) {
NSLog(@"newArray3%@----%@",person.name,person.age);
}
NSPredicate * newChangePre3 = [changePre2 predicateWithSubstitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:@"ang",@"SUBSTR", nil]];
NSArray * newArray4 = [array2 filteredArrayUsingPredicate:newChangePre3];
for (CXHPerson * person in newArray4) {
NSLog(@"newArray4%@----%@",person.name,person.age);
}
//輸出結(jié)果:
2018-02-27 23:07:11.820 CXHNSPredicate[4540:96427] newArray2sunny----30
2018-02-27 23:07:11.820 CXHNSPredicate[4540:96427] newArray3sunny----30
2018-02-27 23:07:11.820 CXHNSPredicate[4540:96427] newArray4zhang san----21
那么至此NSPredicate就到到此介紹完畢中剩。
關(guān)于謂詞的使用,我們只列舉了幾個(gè)常見的用法抒寂,它還有很多種靈活的用法结啼,如對時(shí)間datetime的間隔篩選、謂詞變量 ”謂詞==$變量名“等屈芜,待有時(shí)間希望大家去研究郊愧。