天天看点

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));

}];