天天看点

Swift基础之NSDataDetector数据检查器(类似于正则表达式的作用)

在iOS开发中,有一个简单的对于寻找数据的解决方案:NSDataDetector。

NSDataDetector是继承NSRegularExpression(iOS中的正则表达式)的一个子类,你可以把它看作一个正则表达式匹配器和令人难以置信的复杂的表达式,可以从自然语言(虽然可能更复杂)中提取你想要的信息。主要用于检测半结构化的数据:日期,地址,电话号码,正则表达式等等。

OC使用:

//检测是否是有链接地址 或 电话号码,并输出匹配结果
    //(注意:字符串的设置要将不同的内容用 空格 进行分割,否则内容会被看成整体,从而无法识别)
    NSString *testStr = @"123 Hello World! www.baidu.com Stt. / 18337101863 sdfgrge";
    
    //初始化检测,设置NSTextCheckingType类型
    /*
     NSTextCheckingTypes:一种是系统的,一种是自定义的
     部分系统的:
     typedef NS_OPTIONS(uint64_t, NSTextCheckingType) {    // a single type
     NSTextCheckingTypeOrthography           = 1ULL << 0,            // language identification
     NSTextCheckingTypeSpelling              = 1ULL << 1,            // spell checking
     NSTextCheckingTypeGrammar               = 1ULL << 2,            // grammar checking
     NSTextCheckingTypeDate                  = 1ULL << 3,            // date/time detection
     NSTextCheckingTypeAddress               = 1ULL << 4,            // address detection
     NSTextCheckingTypeLink                  = 1ULL << 5,            // link detection
     NSTextCheckingTypeQuote                 = 1ULL << 6,            // smart quotes
     NSTextCheckingTypeDash                  = 1ULL << 7,            // smart dashes
     NSTextCheckingTypeReplacement           = 1ULL << 8,            // fixed replacements, such as copyright symbol for (c)
     NSTextCheckingTypeCorrection            = 1ULL << 9,            // autocorrection
     NSTextCheckingTypeRegularExpression NS_ENUM_AVAILABLE(10_7, 4_0)  = 1ULL << 10,           // regular expression matches
     NSTextCheckingTypePhoneNumber NS_ENUM_AVAILABLE(10_7, 4_0)        = 1ULL << 11,           // phone number detection
     NSTextCheckingTypeTransitInformation NS_ENUM_AVAILABLE(10_7, 4_0) = 1ULL << 12            // transit (e.g. flight) info detection
     };
     
     */
    NSError *error = nil;
    //(注意:当初始化NSDataDetector的时候,只指定自己需要的类型(Type)就可以了,因为多增加一项就会多一些内存的开销。)
    NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink | NSTextCheckingTypePhoneNumber error:&error];
    
    //---------------- 有多种方法检测匹配的数据
    //1.检测然后对每个检测到的数据进行操作
    //- (void)enumerateMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range usingBlock:(void (^)(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop))block;
    //2.检测获得检测得到的数组
    //- (NSArray *)matchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
    //3.获得检测得到的总数
    //- (NSUInteger)numberOfMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
    //4.第一个检测到的数据
    //- (NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
    //5.第一检测到的数据的Range
    //- (NSRange)rangeOfFirstMatchInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
    
    //方法一:使用block块,输出匹配的结果
    [detector enumerateMatchesInString:testStr options:kNilOptions range:NSMakeRange(0, [testStr length])usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {

        //NSTextCheckingResult有很多属性,和检测的类型相匹配,如URL,phoneNumber,date,addressComponents等等
        //NSTextCheckingResult还有range 和 resultType两个属性,方便进行操作
        if (result.resultType == NSTextCheckingTypeLink) {
            NSLog(@"方法一...检测是否是有 链接地址: %@", result);
            NSLog(@"方法一...链接地址 的范围: %@",NSStringFromRange(result.range));
            NSLog(@"方法一...链接地址: %@",result.URL);
        }
        if (result.resultType == NSTextCheckingTypePhoneNumber) {
            NSLog(@"方法一...检测是否是有 电话号码: %@", result);
            NSLog(@"方法一...电话号码 的范围: %@",NSStringFromRange(result.range));
            NSLog(@"方法一...电话号码: %@",result.phoneNumber);
        }
    }];
    //方法二:获取数组,输出检测结果
    NSArray *matchesArr = [detector matchesInString:testStr options:0 range:NSMakeRange(0, testStr.length)];//检测字符串
    for (NSTextCheckingResult *matchResult in matchesArr) {
        if (matchResult.resultType == NSTextCheckingTypeLink) {
            NSLog(@"方法二...检测是否是有 链接地址: %@", matchResult);
            NSLog(@"方法二...链接地址 的范围: %@",NSStringFromRange(matchResult.range));
            NSLog(@"方法二...链接地址: %@",matchResult.URL);
        }
        if (matchResult.resultType == NSTextCheckingTypePhoneNumber) {
            NSLog(@"方法二...检测是否是有 电话号码: %@", matchResult);
            NSLog(@"方法二...电话号码 的范围: %@",NSStringFromRange(matchResult.range));
            NSLog(@"方法二...电话号码: %@",matchResult.phoneNumber);
        }
    }           

结果展示:

Swift基础之NSDataDetector数据检查器(类似于正则表达式的作用)

Swift使用:

/**
     匹配字符串中所有的URL
     */
    private func getUrls(str:String) -> [String] {
        var urls = [String]()
        // 创建一个正则表达式对象
        do {
            let dataDetector = try NSDataDetector(types:
                NSTextCheckingTypes(NSTextCheckingResult.CheckingType.link.rawValue))
            // 匹配字符串,返回结果集
            let res = dataDetector.matches(in: str, options:NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, str.characters.count))
            // 取出结果
            for checkingRes in res {
                urls.append((str as NSString).substring(with: checkingRes.range))
            }
        }
        catch {
            print(error)
        }
        return urls
    }
    
    /**
     验证URL格式是否正确
     */
    private func verifyUrl(str:String) -> Bool {
//        // 创建一个正则表达式对象
//        do {
//            let dataDetector = try NSDataDetector(types:
//                NSTextCheckingTypes(NSTextCheckingResult.CheckingType.link.rawValue))
//            // 匹配字符串,返回结果集
//            let res = dataDetector .matches(in: str, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, str.characters.count))
//            // 判断结果(完全匹配)
//            if res.count == 1  && res[0].range.location == 0
//                && res[0].range.length == str.characters.count {
//                return true
//            }
//        }
//        catch {
//            print(error)
//        }
//        return false
        
        //注意:验证URL链接更简单的办法 我们还可以借助系统提供的 canOpenURL() 方法来检测一个链接的有效性
        //创建NSURL实例
        if let url = NSURL(string: str) {
            //检测应用是否能打开这个NSURL实例
            return UIApplication.shared.canOpenURL(url as URL)
        }
        return false
    }           

GitHub源码下载Demo:https://github.com/hbblzjy/Swift-NSDataDetector

如果你想在UILabel中简单地使用NSDataDetector,可以看看TTTAttributedLabel 的源码框架:http://www.jianshu.com/p/b457a49fac3d