NSPredicateで使用できる全構文の解説です。
確認に使用したサンプルコードはこちらです。
NSPredicate Programming Guide - Predicate Format String Syntaxに記載しているのは全て取り上げていますが、SUBQUERYがNSExpressionに書いてあったりしたからまだ他にもあるのかもしれません。
あと@を指定して使用する関数のドキュメントが見つからなかった・・・ドキュメントが乱雑し整理されていない感じがしました。
関連キーワード: BNF, NSExpression
注意: SQLと同じ用語には注意が必要です。例えばANYはSQLのANYとは異なります。
リテラル
%@
文字列として扱われる(ダブルクォーテーションで囲われる)
NSString *attributeValue = @"Anne";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"firstName LIKE %@", attributeValue];
// predicate: firstName LIKE "Anne"
%K
動的プロパティとして扱われる(ダブルクォーテーションで囲われない)
NSString *attributeName = @"firstName";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K LIKE \'Anne\'", attributeName];
// predicate: firstName LIKE "Anne"
{ 'comma', 'separated', 'literal', 'array' }
カンマで区切られたリテラル配列の表記
SELF
評価されるオブジェクト自身
FALSE, NO
false
TRUE, YES
true
NULL, NIL
null
"text" , 'text'
文字列。"text"と'text'は同じ。混在時に注意("a'b'c" は a, 'b', c と相当)
1, 27, 2.71828, 19.75
整数と固定小数点表記
9.2e-5
累乗と浮動小数点表記
0x
16進数
0o
8進数
0b
2進数
比較
=, ==
左辺値と右辺値が等しい
>=, =>
左辺値は右辺値以上
<=, =<
左辺値は右辺値以下
>
左辺値は右辺値を超える
<
左辺値は右辺値未満
!=, <>
左辺値と右辺値は等しくない
BETWEEN
array[0]以上、array[1]以下
NSPredicate *betweenPredicate = [NSPredicate predicateWithFormat: @"attributeName BETWEEN %@", @[@1, @10]];
// ((1 <= attributeValue ) && ( attributeValue <= 10))
BOOL値
TRUEPREDICATE
常にTRUEで評価される
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"TRUEPREDICATE"];
NSLog(@"evaluate: %@", @([predicate evaluateWithObject:[self users]]));
// evaluate: 1
NSLog(@"all users: %@", [[self users] filteredArrayUsingPredicate:predicate]);
/*
all users: (
"firstName: Herbert, lastName: Korberg, age: 20, gender: 1",
"firstName: Anne, lastName: Nordenskiold, age: 24, gender: 0",
"firstName: Juanito, lastName: Suela, age: 35, gender: 1",
"firstName: Rebecca, lastName: Vinci, age: 14, gender: 0",
"firstName: %@, lastName: Vinci, age: 14, gender: 0"
)
*/
FALSEPREDICATE
常にFALSEで評価される
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"FALSEPREDICATE"];
NSLog(@"evaluate: %@", @([predicate evaluateWithObject:[self users]]));
// evaluate: 0
NSLog(@"all users: %@", [[self users] filteredArrayUsingPredicate:predicate]);
/*
all users: (
)
*/
論理演算
AND, &&
論理積
OR, ||
論理和
NOT, !
否定
文字列の比較
BEGINSWITH
右辺値から始まる文字列か
CONTAINS
右辺値が含まれているか
ENDSWITH
右辺値で終わる文字列か
LIKE
右辺値と完全一致するか
ワイルドカードとして「*」「?」が使用可能(*は0文字以上一致、?は1文字以上一致)
MATCHES
正規表現(ICU v3)
文字列比較のオプション
c
大文字・小文字の区別なし(case-insensitive)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"firstName LIKE[c] \'anne\'", attributeName];
NSLog(@"%@", [[self users] filteredArrayUsingPredicate:predicate]);
/*
(
"firstName: Anne, lastName: Nordenskiold, age: 24, gender: 0"
)
*/
d
ダイアクリティカルマークを無視する(diacritic-insensitive)
NSPredicate *pridicate = [NSPredicate predicateWithFormat:@"firstName LIKE[d] \'Marka\'"];
NSLog(@"%@", [[self users] filteredArrayUsingPredicate:pridicate]);
/*
(
"firstName: Márkä, lastName: Chèrêpkõv, age: 50, gender: 0"
)
*/
集計操作
比較で左辺値が多の要素の場合、ANY, ALL, NONEのいずれかを指定する必要がある。
ANY, SOME
いずれかの要素が条件と一致する
// 1999年以降の書籍を1つ以上持っているか
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY books.year > 1999"];
NSLog(@"%@", [[self library].authors filteredArrayUsingPredicate:predicate]);
/*
(
"<name: Herbert; books: {(<title: AAA; year: 1990>, <title: BBB; year: 2000>, <title: CCC; year: 2010>)}>",
"<name: Juanito; books: {(<title: EEE; year: 2001>)}>"
)
*/
※ authorなので持っているかではなくて書いているかだけど意味が伝わりやすいように変更してる
ALL
全ての要素が条件と一致する
// 1999年以降の書籍のみ持っているか
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ALL books.year > 1999"];
NSLog(@"%@", [[self library].authors filteredArrayUsingPredicate:predicate]);
/*
(
"<name: Juanito; books: {(<title: EEE; year: 2001>)}>"
)
*/
NONE
全ての要素が条件と一致しない
// 1999年以降の書籍を1つも持っていない
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NONE books.year > 1999"];
NSLog(@"%@", [[self library].authors filteredArrayUsingPredicate:predicate]);
/*
(
"<name: Anne; books: {(<title: DDD; year: 1991>)}>"
)
*/
IN
いずれかの条件と一致する(SQLのIN相当)
// 名前がAnneまたはJuanitoか
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name IN %@", @[@"Anne", @"Juanito"]];
NSArray *filterdArray = [[self library].authors filteredArrayUsingPredicate:predicate];
NSLog(@"%@", filterdArray);
/*
(
"<name: Anne; books: {(<title: DDD; year: 1991>)}>",
"<name: Juanito; books: {(<title: EEE; year: 2001>)}>"
)
*/
SUBQUERY
サブクエリ
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SUBQUERY(books, $s, $s.year > 2000 AND $s.year < 2010).@count > 0"];
NSArray *filterdArray = [[self library].authors filteredArrayUsingPredicate:predicate];
NSLog(@"%s; %@", __func__, filterdArray);
/*
(
"<name: Juanito; books: {(<title: EEE; year: 2001>)}>"
)
*/
2次元配列の条件一致
array[index]
配列の配列でindexの要素らが条件と一致
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF[1] = '2-B'"];
NSArray *filterdArray = [[self schoolClasses] filteredArrayUsingPredicate:predicate];
NSLog(@"%@", filterdArray);
/*
(
(
"2-A",
"2-B"
)
)
*/
array[FIRST]
配列の配列で1番目の要素らが条件と一致
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF[FIRST] = '1-A'"];
NSArray *filterdArray = [[self schoolClasses] filteredArrayUsingPredicate:predicate];
NSLog(@"%@", filterdArray);
/*
(
(
"1-A",
"1-B",
"1-C"
)
)
*/
array[LAST]
配列の配列で最後の要素らが条件と一致
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF[LAST] = '1-C'"];
NSArray *filterdArray = [[self schoolClasses] filteredArrayUsingPredicate:predicate];
NSLog(@"%@", filterdArray);
/*
(
(
"1-A",
"1-B",
"1-C"
)
)
*/
array[SIZE]
配列の配列でサイズが条件と一致するか
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF[SIZE] = 2"];
NSArray *filterdArray = [[self schoolClasses] filteredArrayUsingPredicate:predicate];
/*
(
(
"2-A",
"2-B"
)
)
*/
識別子
C言語の識別子
#symbol
予約語のエスケープ
[\]{octaldigit}{3}
8進数のエスケープ(\)
[\][xX]{hexdigit}{2}
16進数のエスケープ(\x, \X)
[\][uU]{hexdigit}{4}
Unicodeのエスケープ(\u, \U)
予約語
AND, OR, IN, NOT, ALL, ANY, SOME, NONE, LIKE, CASEINSENSITIVE, CI, MATCHES, CONTAINS, BEGINSWITH, ENDSWITH, BETWEEN, NULL, NIL, SELF, TRUE, YES, FALSE, NO, FIRST, LAST, SIZE, ANYKEY, SUBQUERY, CAST, TRUEPREDICATE, FALSEPREDICATE