天天看點

iOS小技能:NSPredicate在正規表達式的應用

引言

日常開發中,優雅高效的代碼離不開Predicate的應用。

格式化字元串​​可以被看作三部分:左手表達式、邏輯符号和右手表達式。​​

其中,左手表達式是一個對象的屬性鍵值(鍵路徑);

邏輯符号是一個基本的邏輯運算符;

右手表達式是限制範圍。

I 前置知識

Predicate Format String Syntax

1.1 Parser Basics

  • Two important format specifiers are %@ and %K.

%@ is a var arg substitution for an object value—often a string, number, or date.

%K is a var arg substitution for a key path.

NSString *attributeName  = @"firstName";
NSString *attributeValue = @"siting";
NSPredicate *predicate   = [NSPredicate predicateWithFormat:@"%K like %@",
        attributeName, attributeValue];      

1.2 Basic Comparisons

​=, ==​

​​The left-hand expression is equal to the right-hand expression.

​​

​>=, =>​

​​The left-hand expression is greater than or equal to the right-hand expression.

​​

​<=, =<​

​​The left-hand expression is less than or equal to the right-hand expression.

​​

​>​

​​The left-hand expression is greater than the right-hand expression.

​​

​<​

​​The left-hand expression is less than the right-hand expression.

​​

​!=, <>​

​The left-hand expression is not equal to the right-hand expression.

​BETWEEN​

The left-hand expression is between, or equal to either of, the values specified in the right-hand side.

The right-hand side is a two value array (an array is required to specify order) giving upper and lower bounds. For example, 1 BETWEEN { 0 , 33 }, or INPUT BETWEEN { LOWER, $UPPER }.

In Objective-C, you could create a BETWEEN predicate as shown in the following example:

NSPredicate *betweenPredicate =
    [NSPredicate predicateWithFormat: @"attributeName BETWEEN %@", @[@1, @10]];
NSDictionary *dictionary = @{ @"attributeName" : @5 };

BOOL between = [betweenPredicate eval(between) {
    NSLog(@"between");
}      

1.3 Basic Compound Predicates

​AND, &&​

​​Logical AND.

​​

​OR, ||​

​​Logical OR.

​​

​NOT, !​

​Logical NOT.

1.4 String Comparisons

邏輯運算符與SQL語句中的文法基本相對應,除了最基本的邏輯運算符之外,還有邏輯詞IN、CONTAINS、like等。

它們的使用情況如下:

iOS小技能:NSPredicate在正規表達式的應用

​BEGINSWITH​

​​The left-hand expression begins with the right-hand expression.

​​

​CONTAINS​

​​The left-hand expression contains the right-hand expression.

​​

​ENDSWITH​

​​The left-hand expression ends with the right-hand expression.

​​

​LIKE​

The left hand expression equals the right-hand expression: ? and * are allowed as wildcard characters, where ? matches 1 character and * matches 0 or more characters.

MATCHES

The left hand expression equals the right hand expression using a regex-style comparison according to ICU v3 (for more details see the ICU User Guide for Regular Expressions).

UTI-CONFORMS-TO

The left hand argument to this operator is an expression that eval(UTI) you want to match.

The right hand argument is an expression that evaluates to a UTI.

The comparison eval(232, 232, 232); background: rgb(249, 249, 249);">

UTTypeConformsTo (A, B)      

When eval(of type NSExtensionItem), you could use a statement similar to the following:

SUBQUERY (
    extensionItems,
    $extensionItem,
    SUBQUERY (
        $extensionItem.attachments,
        $attachment,
        ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "com.adobe.pdf"
    ).@count == $extensionItem.attachments.@count
).@count == 1      

UTI-EQUALS

The left hand argument to this operator is an expression that eval(UTI) you want to match.

The right hand argument is an expression that evaluates to a UTI.

The comparison evaluates to TRUE if the UTI returned by the left hand expression equals the UTI returned by the right hand expression.

The clause A UTI-EQUALS B provides the same result as employing the UTTypeEqual method as follows:

UTTypeEqual (A, B)      

1.5 Aggregate Operations

ANY, SOME

Specifies any of the elements in the following expression. For example ANY children.age < 18.

ALL

Specifies all of the elements in the following expression. For example ALL children.age < 18.

NONE

Specifies none of the elements in the following expression. For example, NONE children.age < 18. This is logically equivalent to NOT (ANY ...).

IN

Equivalent to an SQL IN operation, the left-hand side must appear in the collection specified by the right-hand side.

For example, name IN { 'Ben', 'Melissa', 'Nick' }. The collection may be an array, a set, or a dictionary—in the case of a dictionary, its values are used.

In Objective-C, you could create a IN predicate as shown in the following example:

NSPredicate *inPredicate =
            [NSPredicate predicateWithFormat: @"attribute IN %@", aCollection];      
where aCollection may be an instance of NSArray, NSSet, NSDictionary, or of any of the corresponding mutable classes.

array[index]

Specifies the element at the specified index in the array array.

array[FIRST]

Specifies the first element in the array array.

array[LAST]

Specifies the last element in the array array.

array[SIZE]

Specifies the size of the array array.

1.6 Identifiers

C style identifier

Any C style identifier that is not a reserved word.

#symbol

Used to escape a reserved word into a user identifier.

​[\]{octaldigit}{3}​

Used to escape an octal number ( \ followed by 3 octal digits).

​[\][xX]{hexdigit}{2}​

Used to escape a hex number ( \x or \X followed by 2 hex digits).

​[\][uU]{hexdigit}{4}​

Used to escape a Unicode number ( \u or \U followed by 4 hex digits).

1.7 Literals

FALSE, NO

Logical false.

TRUE, YES

Logical true.

NULL, NIL

A null value.

SELF

Represents the object being eval(238, 238, 238); opacity: 0.6;">

A character string.

'text'

A character string.

Comma-separated literal array

For example, { 'comma', 'separated', 'literal', 'array' }.

Standard integer and fixed-point notations

For example, 1, 27, 2.71828, 19.75.

Floating-point notation with exponentiation

For example, 9.2e-5.

0x

Prefix used to denote a hexadecimal digit sequence.

0o

Prefix used to denote an octal digit sequence.

0b

Prefix used to denote a binary digit sequence.

1.8 Reserved Words

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, FETCH, CAST, TRUEPREDICATE, FALSEPREDICATE, UTI-CONFORMS-TO, UTI-EQUALS,

II NSPredicate在正規表達式的應用

2.1 商品分類名稱

僅支援數字、字母、中文、斜杠\、橫杠",且不能以符号開頭

iOS小技能:NSPredicate在正規表達式的應用

“-”這個連接配接符需要轉義-,否則報如下的錯誤

"Can't do regex matching, reason: Can't open pattern U_REGEX_MISSING_CLOSE_BRACKET (string U, pattern ^[0-9a-zA-Z一-龥][0-9a-zA-Z一-龥-\\]{0,}$, case 0, canon 0)"      

OC正确的寫法:

​\\\​

​​表示斜杠​

​\​

​ 轉義符

​\-​

​​代表橫杆​

​-​

​ 連接配接符

BOOL)checkProductClassName: (NSString *) name
{
    NSString *pattern = @"^[0-9a-zA-Z\u4E00-\u9FA5][0-9a-zA-Z\u4E00-\u9FA5\\\\-]{0,}$";//
    NSLog(@"KN-pattern:%@",pattern);//2022-07-22 11:01:26.641648+0800 retail[5321:1883667] KN-pattern:^[0-9a-zA-Z一-龥][0-9a-zA-Z一-龥\\-]{0,}$

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
    BOOL isMatch = [pred eval(232, 232, 232); background: rgb(249, 249, 249);">       
pattern: /^[0-9a-zA-Z\u4E00-\u9FA5][0-9a-zA-Z\u4E00-\u9FA5-\\]{0,}$/,      

2.2 基本校驗例子

正則比對使用者密碼6-16位數字和字母組合

BOOL)checkPassword:(NSString *) password
{
    NSString *pattern = @"^(?![0-9]+$)(?![a-zA-Z]+$)[a-zA-Z0-9]{6,16}";

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];

    BOOL isMatch = [pred eval(232, 232, 232); background: rgb(249, 249, 249);">       
BOOL)checkTelNumber:(NSString *) telNumber
{
    NSString *pattern = @"^1+[3578]+\\d{9}";
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
    BOOL isMatch = [pred eval(BOOL)checkEmployeeNumber : (NSString *) number
{
    NSString *pattern = @"^[0-9]{12}";

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
    BOOL isMatch = [pred eval(232, 232, 232); background: rgb(249, 249, 249);">       
BOOL)checkUserName : (NSString *) userName
{
    NSString *pattern = @"^[a-zA-Z\u4E00-\u9FA5]{1,20}";
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
    BOOL isMatch = [pred eval(BOOL)checkUserIdCard: (NSString *) idCard
{
    NSString *pattern = @"(^[0-9]{15}$)|([0-9]{17}([0-9]|X)$)";
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
    BOOL isMatch = [pred eval(232, 232, 232); background: rgb(249, 249, 249);">       
+ (BOOL)checkURL : (NSString *) url
{
    NSString *pattern = @"^[0-9A-Za-z]{1,50}";
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
    BOOL isMatch = [pred eval(232, 232, 232); background: rgb(249, 249, 249);">       
+ (BOOL)isAmoutshouldChangeCharactersInRange:(NSString*)str{
    //比對以0開頭的數字
    NSPredicate * predicate0 = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",@"^[0][0-9]+$"];
    //比對兩位小數、整數
    NSPredicate * predicate1 = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",@"^(([1-9]{1}[0-9]*|[0])\.?[0-9]{0,2})$"];
    return ![predicate0 eval(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{


        NSInteger len = range.length > 0?([textField.text length] - range.length): ([textField.text length] + [string length]);

        if(len > 20){
            return false;
        }
    ////
    NSString * str = [NSString stringWithFormat:@"%@%@",textField.text,string];

    return      

2.4 Url格式校驗

+(BOOL)isUrl:(NSString *)url{
    NSString *regex =@"[a-zA-z]+://[^\\s]*";
    NSPredicate *urlTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex];
    return      
  • 用法舉例:自定義NSURLProtocol, 決定請求是否需要目前協定對象處理
/**
 決定請求是否需要目前協定對象處理

*/
+(BOOL)canInitWithRequest:(NSURLRequest *)request{

    if ([NSURLProtocol propertyForKey:protocolKey inRequest:request]) {
        return NO;
    }
    NSString * url = request.URL.absoluteString;
    return [self      

2.5 判斷字元串是否為IP位址

/**
 * 判斷字元串是否為IP位址
 * param iPAddress IP位址字元串
 * return BOOL 是傳回YES,否傳回NO
 */
+ (BOOL)isIPAddress:(NSString *)iPAddress{
    NSString *pattern = @"^(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5]).(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5]).(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5]).(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])$";
    return [self isText:iPAddress pattern:pattern];

}

+ (BOOL)isText:(NSString *)text pattern:(NSString *)pattern{
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",pattern];
    return      

2.6 正規表達式的一些元字元

元字元 描述
\ 将下一個字元标記為一個特殊字元、或一個原義字元、或一個向後引用、或一個八進制轉義符。例如,“\n”比對\n。“\n”比對換行符。序列“\”比對“\”而“(”則比對“(”。
比對輸入字元串的開始位置。如果設定了RegExp對象的Multiline屬性,^也比對“\n”或“\r”之後的位置。
$ 比對輸入字元串的結束位置。如果設定了RegExp對象的Multiline屬性,$也比對“\n”或“\r”之前的位置。
* 比對前面的子表達式零次或多次(大于等于0次)。例如,zo*能比對“z”,“zo”以及“zoo”。*等價于{0,}。
+ 比對前面的子表達式一次或多次(大于等于1次)。例如,“zo+”能比對“zo”以及“zoo”,但不能比對“z”。+等價于{1,}。
? 比對前面的子表達式零次或一次。例如,“do(es)?”可以比對“do”或“does”中的“do”。?等價于{0,1}。
{n} n是一個非負整數。比對确定的n次。例如,“o{2}”不能比對“Bob”中的“o”,但是能比對“food”中的兩個o。
{n,} n是一個非負整數。至少比對n次。例如,“o{2,}”不能比對“Bob”中的“o”,但能比對“foooood”中的所有o。“o{1,}”等價于“o+”。“o{0,}”則等價于“o*”。
{n,m} m和n均為非負整數,其中n<=m。最少比對n次且最多比對m次。例如,“o{1,3}”将比對“fooooood”中的前三個o。“o{0,1}”等價于“o?”。請注意在逗号和兩個數之間不能有空格。
? 當該字元緊跟在任何一個其他限制符(*,+,?,{n},{n,},{n,m})後面時,比對模式是非貪婪的。非貪婪模式盡可能少的比對所搜尋的字元串,而預設的貪婪模式則盡可能多的比對所搜尋的字元串。例如,對于字元串“oooo”,“o+?”将比對單個“o”,而“o+”将比對所有“o”。
.點 比對除“\r\n”之外的任何單個字元。要比對包括“\r\n”在内的任何字元,請使用像“[\s\S]”的模式。
(pattern) 比對pattern并擷取這一比對。所擷取的比對可以從産生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中則使用9屬性。要比對圓括号字元,請使用“(”或“)”。
(?:pattern) 比對pattern但不擷取比對結果,也就是說這是一個非擷取比對,不進行存儲供以後使用。這在使用或字元“(|)”來組合一個模式的各個部分是很有用。例如“industr(?:y|ies)”就是一個比“industry|industries”更簡略的表達式。
(?=pattern) 正向肯定預查,在任何比對pattern的字元串開始處比對查找字元串。這是一個非擷取比對,也就是說,該比對不需要擷取供以後使用。例如,“Windows(?=95|98|NT|2000)”能比對“Windows2000”中的“Windows”,但不能比對“Windows3.1”中的“Windows”。預查不消耗字元,也就是說,在一個比對發生後,在最後一次比對之後立即開始下一次比對的搜尋,而不是從包含預查的字元之後開始。
(?!pattern) 正向否定預查,在任何不比對pattern的字元串開始處比對查找字元串。這是一個非擷取比對,也就是說,該比對不需要擷取供以後使用。例如“Windows(?!95|98|NT|2000)”能比對“Windows3.1”中的“Windows”,但不能比對“Windows2000”中的“Windows”。
(?<=pattern) 反向肯定預查,與正向肯定預查類似,隻是方向相反。例如,“(?<=95|98|NT|2000)Windows”能比對“2000Windows”中的“Windows”,但不能比對“3.1Windows”中的“Windows”。
(?<!pattern) 反向否定預查,與正向否定預查類似,隻是方向相反。例如“(?<!95|98|NT|2000)Windows”能比對“3.1Windows”中的“Windows”,但不能比對“2000Windows”中的“Windows”。
x|y 比對x或y。例如,“z|food”能比對“z”或“food”。“(z|f)ood”則比對“zood”或“food”。
[xyz] 字元集合。比對所包含的任意一個字元。例如,“[abc]”可以比對“plain”中的“a”。
[^xyz] 負值字元集合。比對未包含的任意字元。例如,“[^abc]”可以比對“plain”中的“plin”。
[a-z] 字元範圍。比對指定範圍内的任意字元。例如,“[a-z]”可以比對“a”到“z”範圍内的任意小寫字母字元。注意:隻有連字元在字元組内部時,并且出現在兩個字元之間時,才能表示字元的範圍; 如果出字元組的開頭,則隻能表示連字元本身.
[^a-z] 負值字元範圍。比對任何不在指定範圍内的任意字元。例如,“[^a-z]”可以比對任何不在“a”到“z”範圍内的任意字元。
\b 比對一個單詞邊界,也就是指單詞和空格間的位置。例如,“er\b”可以比對“never”中的“er”,但不能比對“verb”中的“er”。
\B 比對非單詞邊界。“er\B”能比對“verb”中的“er”,但不能比對“never”中的“er”。
\cx 比對由x指明的控制字元。例如,\cM比對一個Control-M或回車符。x的值必須為A-Z或a-z之一。否則,将c視為一個原義的“c”字元。
\d 比對一個數字字元。等價于[0-9]。
\D 比對一個非數字字元。等價于[^0-9]。
\f 比對一個換頁符。等價于\x0c和\cL。
\n 比對一個換行符。等價于\x0a和\cJ。
\r 比對一個回車符。等價于\x0d和\cM。
\s 比對任何空白字元,包括空格、制表符、換頁符等等。等價于[ \f\n\r\t\v]。
\S 比對任何非空白字元。等價于[^ \f\n\r\t\v]。
\t 比對一個制表符。等價于\x09和\cI。
\v 比對一個垂直制表符。等價于\x0b和\cK。
\w 比對包括下劃線的任何單詞字元。等價于“[A-Za-z0-9_]”。
\W 比對任何非單詞字元。等價于“[^A-Za-z0-9_]”。
\xn 比對n,其中n為十六進制轉義值。十六進制轉義值必須為确定的兩個數字長。例如,“\x41”比對“A”。“\x041”則等價于“\x04&1”。正規表達式中可以使用ASCII編碼。
\num 比對num,其中num是一個正整數。對所擷取的比對的引用。例如,“(.)\1”比對兩個連續的相同字元。
\n 辨別一個八進制轉義值或一個向後引用。如果\n之前至少n個擷取的子表達式,則n為向後引用。否則,如果n為八進制數字(0-7),則n為一個八進制轉義值。
\nm 辨別一個八進制轉義值或一個向後引用。如果\nm之前至少有nm個獲得子表達式,則nm為向後引用。如果\nm之前至少有n個擷取,則n為一個後跟文字m的向後引用。如果前面的條件都不滿足,若n和m均為八進制數字(0-7),則\nm将比對八進制轉義值nm。
\nml 如果n為八進制數字(0-7),且m和l均為八進制數字(0-7),則比對八進制轉義值nml。
\un 比對n,其中n是一個用四個十六進制數字表示的Unicode字元。例如,\u00A9比對版權符号(©)。
< > 比對詞(word)的開始(<)和結束(>)。例如正規表達式<the>能夠比對字元串"for the wise"中的"the",但是不能比對字元串"otherwise"中的"the"。注意:這個元字元不是所有的軟體都支援的。
( ) 将 ( 和 ) 之間的表達式定義為“組”(group),并且将比對這個表達式的字元儲存到一個臨時區域(一個正規表達式中最多可以儲存9個),它們可以用 \1 到\9 的符号來引用。
| 将兩個比對條件進行邏輯“或”(Or)運算。例如正規表達式(him|her) 比對"it belongs to him"和"it belongs to her",但是不能比對"it belongs to them."。注意:這個元字元不是所有的軟體都支援的。
+ 比對1或多個正好在它之前的那個字元。例如正規表達式9+比對9、99、999等。注意:這個元字元不是所有的軟體都支援的。
? 比對0或1個正好在它之前的那個字元。注意:這個元字元不是所有的軟體都支援的。
{i} {i,j} 比對指定數目的字元,這些字元是在它之前的表達式定義的。例如正規表達式A[0-9]{3} 能夠比對字元"A"後面跟着正好3個數字字元的串,例如A123、A348等,但是不比對A1234。而正規表達式[0-9]{4,6} 比對連續的任意4個、5個或者6個數字

III 從數組搜尋特定條件的元素

從數組中篩選type=8的電子簽名資料,避免周遊數組 certificateInfoList

————————————————

版權聲明:本文為部落客「#公衆号:iOS逆向」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。

iOS小技能:NSPredicate在正規表達式的應用

see also

公衆号:iOS逆向

  • 打賞
  • 收藏
  • 評論
  • 分享
  • 舉報

上一篇:iOS小技能:裝置ID除了使用_idfa、_idfv 還可使用其他替代方案(使用Keychain 存儲UUID)

下一篇:iOS小技能:參數名ASCII碼從小到大排序、對象數組排序

舉封包章

請選擇舉報類型

内容侵權

涉嫌營銷

内容抄襲

違法資訊

其他

具體原因

包含不真實資訊

涉及個人隐私

原文連結(必填)

補充說明

取消

确認

已經收到您得舉報資訊,我們會盡快稽核

iOS小技能:NSPredicate在正規表達式的應用

提問和評論都可以,用心的回複會被更多人看到

評論

釋出評論

全部評論

(

)

最熱

最新

{{value.nickname}}

{{if value.is_author == 1}}

部落客

{{/if}}

{{value.create_time}}

{{value.content}}

{{if value.is_reply == 1}}

回複

{{/if}}

點贊

{{value.up_num>0 ? value.up_num : ''}}

{{if value.is_delete == 1}}

删除

{{/if}}

{{if value.children.total > 0}}

{{each value.children.list item key}}

3}}style="display:none;"{{/if}}>

iOS小技能:NSPredicate在正規表達式的應用

{{if item.is_vip == 1}}

{{/if}}

{{item.nickname}}

{{if item.is_author == 1}}

部落客

{{/if}}

回複了

{{item.reply_nickname}} {{item.create_time}}

{{if item.is_reply_content>0}}

{{item.reply_content}}

{{/if}}

{{item.content}}

{{if item.is_reply == 1}}

回複

{{/if}}

點贊

{{item.up_num>0 ? item.up_num : ''}}

{{if item.is_delete == 1}}

删除

{{/if}}

{{if key == 3}}

檢視更多回複

{{/if}}

{{/each}}

{{/if}}