天天看點

iOS - 正規表達式

在iOS開發過程中,我們經常會涉及到這樣的功能例如:校驗手機号、身份證号這樣的功能,我們該如何快速有效的實作這樣的功能呢?正規表達式是一種通用的、常用的方式,優秀的正規表達式可以讓你少寫千行代碼。這裡給大家列舉幾種常用的正規表達式。

正規表達式應用執行個體

1. 手機号碼正規表達式驗證

1) 部落客對部分号段做了補充(17、14号段)如有補充 評論即可 我會及時回複

- (BOOL)isMobileNumber:(NSString *)mobileNum
{
    /**
     * 手機号碼
     * 移動:134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188
     * 聯通: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         * 中國聯通: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         * 大陸地區固話及小靈通
     26         * 區号:010,020,021,022,023,024,025,027,028,029
     27         * 号碼:七位或八位
     28         */

    // NSString * PHS = @"^0(10|2[0-5789]|\\d{3})\\d{7,8}$";

    /**
     29        * 其他号段補充:
     30        * 号段:170、176、177、178、145、147
     31        * 号碼:八位
     32        */

     NSString *OT = @"^((17[0678])|(14[57]))\\d{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];
    NSPredicate *regextestot = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", OT];

    if (([regextestmobile evaluateWithObject:mobileNum] == YES)
        || ([regextestcm evaluateWithObject:mobileNum] == YES)
        || ([regextestct evaluateWithObject:mobileNum] == YES)
        || ([regextestcu evaluateWithObject:mobileNum] == YES)
        || ([regextestot evaluateWithObject:mobileNum] == YES))
    {
        return YES;
    }
    else
    {
        return NO;
    }
}
           

2) 這個是秋秋同學提供的

+ (BOOL)validateMobile:(NSString *)mobile{ 
 //手機号以13, 15,17,18開頭,八個 \d 數字字元 
 NSString *phoneRegex = @"^((13[0-9])|(17[0])|(17[7])|(14[57])|(15[012356789])|(17[678])|(18[0-9]))\\d{8}$"; NSPredicate *phoneTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",phoneRegex];
return [phoneTest evaluateWithObject:mobile];
 }
           

2. 身份證号碼正規表達式驗證

這個校驗是比較全面和詳細的

- (BOOL)validateIDCardNumber:(NSString *)value {

    value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

    NSUInteger length =;

    if (!value) {

        return NO;

    }else {

        length = value.length;

        if (length != && length !=) {

            return NO;

        }

    }

    // 省份代碼

    NSArray *areasArray [email protected][@"11",@"12", @"13",@"14", @"15",@"21", @"22",@"23", @"31",@"32", @"33",@"34", @"35",@"36", @"37",@"41",@"42",@"43", @"44",@"45", @"46",@"50", @"51",@"52", @"53",@"54", @"61",@"62", @"63",@"64", @"65",@"71", @"81",@"82", @"91"];

    NSString *valueStart2 = [value substringToIndex:];

    BOOL areaFlag = NO;

    for (NSString *areaCode in areasArray) {

        if ([areaCode isEqualToString:valueStart2]) {

            areaFlag = YES;

            break;

        }

    }

    if (!areaFlag) {

        return NO;
    }

    NSRegularExpression *regularExpression;

    NSUInteger numberofMatch;

    int year = ;

    switch (length) {

        case :

            year = [value substringWithRange:NSMakeRange(,)].intValue +;

            if (year % ==  || (year % ==  && year %  == )) {

                regularExpression = [[NSRegularExpression alloc]initWithPattern:@"^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$" options:NSRegularExpressionCaseInsensitive error:nil];//測試出生日期的合法性

            }else {

                regularExpression = [[NSRegularExpression alloc]initWithPattern:@"^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$"                      options:NSRegularExpressionCaseInsensitive error:nil];//測試出生日期的合法性

            }


            numberofMatch = [regularExpression numberOfMatchesInString:value options:NSMatchingReportProgress range:NSMakeRange(, value.length)];

            if(numberofMatch >) {

                return YES;

            }else {

                return NO;

            }

        case :

            year = [value substringWithRange:NSMakeRange(,)].intValue;

            if (year % == || (year % == && year % ==)) {

                regularExpression = [[NSRegularExpression alloc]initWithPattern:@"^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$" options:NSRegularExpressionCaseInsensitive error:nil];//測試出生日期的合法性
            }else {

                regularExpression = [[NSRegularExpression alloc]initWithPattern:@"^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$" options:NSRegularExpressionCaseInsensitive error:nil];//測試出生日期的合法性

            }
            numberofMatch = [regularExpression numberOfMatchesInString:value options:NSMatchingReportProgress range:NSMakeRange(, value.length)];

            if(numberofMatch >) {

                int S = ([value substringWithRange:NSMakeRange(,)].intValue + [value substringWithRange:NSMakeRange(,)].intValue) * + ([value substringWithRange:NSMakeRange(,)].intValue + [value substringWithRange:NSMakeRange(,)].intValue) * + ([value substringWithRange:NSMakeRange(,)].intValue + [value substringWithRange:NSMakeRange(,)].intValue) * + ([value substringWithRange:NSMakeRange(,)].intValue + [value substringWithRange:NSMakeRange(,)].intValue) * + ([value substringWithRange:NSMakeRange(,)].intValue + [value substringWithRange:NSMakeRange(,)].intValue) * + ([value substringWithRange:NSMakeRange(,)].intValue + [value substringWithRange:NSMakeRange(,)].intValue) * + ([value substringWithRange:NSMakeRange(,)].intValue + [value substringWithRange:NSMakeRange(,)].intValue) * + [value substringWithRange:NSMakeRange(,)].intValue * + [value substringWithRange:NSMakeRange(,)].intValue * + [value substringWithRange:NSMakeRange(,)].intValue *;


                int Y = S %;

                NSString *M =@"F";

                NSString *JYM =@"10X98765432";

                M = [JYM substringWithRange:NSMakeRange(Y,)];// 判斷校驗位

                if ([M isEqualToString:[value substringWithRange:NSMakeRange(,)]]) {

                    return YES;// 檢測ID的校驗位

                }else {

                    return NO;
                }
            }else {

                return NO;

            }


        default:

           return NO;

    }

}
           

這兩個正規表達式是比較常用的,其餘的正規表達式在以後的使用過程中涉及到我會予以補充,也歡迎大家補充說明,我會及時修改補充。

3. 銀行卡号判斷(非正規表達式)

luhn算法,銀行卡的命名以luhn算法為标準。

//-----------------2016年10月3日更新-----------------
- (BOOL) checkCardNo:(NSString*) cardNo{//luhn算法
    int oddsum = ;     //奇數求和
    int evensum = ;    //偶數求和
    int allsum = ;
    int cardNoLength = (int)[cardNo length];
    int lastNum = [[cardNo substringFromIndex:cardNoLength-] intValue];

    cardNo = [cardNo substringToIndex:cardNoLength - ];
    for (int i = cardNoLength - ; i>=;i--) {
        NSString *tmpString = [cardNo substringWithRange:NSMakeRange(i-, )];
        int tmpVal = [tmpString intValue];
        if (cardNoLength %  == ) {
            if((i % ) == ){
                tmpVal *= ;
                if(tmpVal>=)
                    tmpVal -= ;
                evensum += tmpVal;
            }else{
                oddsum += tmpVal;
            }
        }else{
            if((i % ) == ){
                tmpVal *= ;
                if(tmpVal>=)
                    tmpVal -= ;
                evensum += tmpVal;
            }else{
                oddsum += tmpVal;
            }
        }
    }

    allsum = oddsum + evensum;
    allsum += lastNum;
    if((allsum % ) == )
        return YES;
    else
        return NO;
}
           

正規表達式基礎文法規則

【基本文法】

①中括号表示滿足其中之一即可,例如[abc],則這個位置可以是a、b、c中任意一個。

②在中括号中,可以通過-連接配接範圍,例如a-z;多個範圍之間并列不需要任何分隔符,例如[a-zA-Z]。

③表示重複次數用{x},例如[a-z]{2}表示連續2次;表示重複次數的範圍可用{x,y}。

④\d表示數字。

⑤正規表達式預設的是貪婪比對,例如[a-z]{2,4},如果出現類似abcde2ab這樣的字元串,abcd滿足最大長度4,是以會作為一個字元串、e是第二個、ab是第三個。

⑥通配符為.(點),.表示除換行符意外的任意字元。

⑦?表示0個或一個前面的字元、+代表至少一個、*代表0個或多個。

例如zo*,*代表o可以是0個或者多個o,也就是說可以是z、zoo。

⑧以什麼開頭用^,以什麼結尾用$。

⑨OC字元串中的特殊字元用\轉義。

例如[ ]是正則中的特殊表達式,[是普通的‘[‘字元,而OC中\有特殊含義,需要對\再轉義,是以用\[表示‘[‘。

⑩表示中文的範圍為 \u4e00-\u9fa5。

?多個比對條件的并列用|。

比對時一定要注意貪婪比對的問題,否則可能會出錯。

大家可以按照自己的需求修改相應的正規表達式

NSRegularExpression的使用

首先建立對象,然後通過比對模式得到NSTextCheckingResult數組,從中取出對象可以拿到比對到的字元的範圍。

下面的代碼示範了從一個字元串中找出main和if的範圍。

NSString *code = @"mainjiaoififsiifnelsetifajomainiskkl";
 NSString *pattern1 = @"main|if";
 NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:pattern1 options: error:nil];
 NSArray *results = [regex matchesInString:code options: range:NSMakeRange(, code.length)];       
 for (NSTextCheckingResult *result in results) {      
     NSLog(@"%@",NSStringFromRange(result.range));          
 }
           

內建RegexKitLite

利用系統的對象進行比對比較麻煩,下面介紹一個強大的第三方庫RegexKitLite

①首先從github下載下傳RegexKitLite。

②将檔案RegexKitLite.m和.h導入到工程。

③由于該庫比較老,不支援ARC,是以應該為RegexKitLite.m添加編譯标記-fno-objc-arc進行局部ARC禁止。

④添加動态庫libicucore.dylib。

注意③和④都在Build Phases中進行設定,如下圖所示:

iOS - 正規表達式

通過以上幾步就完成了內建,下面介紹該庫的常用方法。

該庫是NSString的分類,是以字元串可以直接調用方法,常用的方法有比對和分割。

①比對:傳入比對模式pattern即可,可以擷取比對到的字元串和範圍。

[str enumerateStringsMatchedByRegex:pattern usingBlock:^(NSInteger captureCount, NSString *const __unsafe_unretained *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {

     NSRange range = *capturedRanges;
     NSLog(@"%@ %@",*capturedStrings,NSStringFromRange(range));

}];
           

②分割:有時候有一種需求,需要擷取到所有比對到的内容之外的字串,也就是利用正則内容分割字元串,可以得到比對到的字串以外的字元串和範圍。

[str enumerateStringsSeparatedByRegex:pattern usingBlock:^(NSInteger captureCount, NSString *const __unsafe_unretained *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {

     NSRange range = *capturedRanges;
     NSLog(@"%@ %@",*capturedStrings,NSStringFromRange(range));

}];