iOS进阶iOS常用

NSRegularExpression的使用

2020-09-11  本文已影响0人  想聽丿伱說衹愛我

版本:iOS13.7

一、简介

NSRegularExpression是利用正则表达式匹配字符串的类,初始化成功后不可更改。
正则表达式的具体语法可查看iOS正则表达式语法全集。使用时若有\b这类字符,需要传入\\b,如"aa\\b"表示查询在在边界的aa字符串,"aa\b"表示的是查询aa\b这个字符串。

二、NSRegularExpression的api

@interface NSRegularExpression : NSObject <NSCopying, NSSecureCoding> 

//通过模式和选顶创建正则表达式
//若模式无效,则返回nil,并通过引用返回error
//pattern 模式,参考 iOS正则表达式语法全集
//options 选项,详见说明1
+ (nullable NSRegularExpression *)regularExpressionWithPattern:(NSString *)pattern 
             options:(NSRegularExpressionOptions)options error:(NSError **)error;
//实例初始化方法
- (nullable instancetype)initWithPattern:(NSString *)pattern
             options:(NSRegularExpressionOptions)options error:(NSError **)error;

//返回正则表达式的模式 只读
@property (readonly, copy) NSString *pattern;
//返回正则表达式的选项 只读 详见说明1
@property (readonly) NSRegularExpressionOptions options;
//返回正则表达式的捕获组数量 只读
@property (readonly) NSUInteger numberOfCaptureGroups;

//将字符串通过\来转义
+ (NSString *)escapedPatternForString:(NSString *)string;

@end
typedef NS_OPTIONS(NSUInteger, NSRegularExpressionOptions) {
   //忽略大小写 "AA"相当于"aa"
   NSRegularExpressionCaseInsensitive             = 1 << 0,
   //忽略空格和#后面的注释 "A B#AA"相当于"AB"
   NSRegularExpressionAllowCommentsAndWhitespace  = 1 << 1,    
   //将整个模式视为文字字符串 "AA\\b"其中的\\b不会当成匹配边界,而是字符串
   NSRegularExpressionIgnoreMetacharacters        = 1 << 2,   
   //允许.匹配任何字符,包括行分隔符。"a.b"可以匹配"a\nb"
   NSRegularExpressionDotMatchesLineSeparators    = 1 << 3,     
   //允许^和$匹配行的开头和结尾(这个好像是一直生效的)
   NSRegularExpressionAnchorsMatchLines           = 1 << 4,    
   //仅将\n视为行分隔符,否则,将使用所有标准行分隔符
   NSRegularExpressionUseUnixLineSeparators       = 1 << 5,     
   //使用Unicode TR#29指定单词边界,否则,使用传统的正则表达式单词边界
   NSRegularExpressionUseUnicodeWordBoundaries    = 1 << 6   
};

三、NSRegularExpression的NSMatching扩展

@interface NSRegularExpression (NSMatching)

//匹配字符串,并在成功匹配时回调一次block
//string 需要匹配的字符串
//options 匹配选项 详见说明2
//range 需要匹配的字符串的范围
//回调block result 匹配的结果,若result.range不为{0, 0}则表示匹配成功
//flags 当前状态 详见说明3
//stop 停止符 当设为YES时,将停止匹配。
//详见例2
- (void)enumerateMatchesInString:(NSString *)string 
        options:(NSMatchingOptions)options range:(NSRange)range 
        usingBlock:(void (NS_NOESCAPE ^)(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL *stop))block;

//匹配字符串,返回匹配结果的数组
//详见例3
- (NSArray<NSTextCheckingResult *> *)matchesInString:(NSString *)string 
            options:(NSMatchingOptions)options range:(NSRange)range;
//匹配字符串,返回匹配结果的数量
//详见例3
- (NSUInteger)numberOfMatchesInString:(NSString *)string 
              options:(NSMatchingOptions)options range:(NSRange)range;
//匹配字符串,返回第一个匹配结果
//详见例3
- (nullable NSTextCheckingResult *)firstMatchInString:(NSString *)string 
             options:(NSMatchingOptions)options range:(NSRange)range;
//匹配字符串,返回第一个匹配结果的范围
//详见例3
- (NSRange)rangeOfFirstMatchInString:(NSString *)string 
             options:(NSMatchingOptions)options range:(NSRange)range;

@end
typedef NS_OPTIONS(NSUInteger, NSMatchingOptions) {
   //在长时间的匹配操作期间,定期回调一次。
   NSMatchingReportProgress         = 1 << 0,       
   //当匹配完成时,回调一次。
   NSMatchingReportCompletion       = 1 << 1,
   //只能匹配查询范围开始处的字符串  "aa"只能匹配"aabcd",而不能匹配"baabcd"       
   NSMatchingAnchored               = 1 << 2,      
   //允许匹配超出搜索范围的范围,例如文字边界检测,前瞻等。如果搜索范围包含整个字符串,该选项将不起作用 
   NSMatchingWithTransparentBounds  = 1 << 3,      
   //防止^和$自动匹配搜索范围的开始和结束,如果搜索范围包含整个字符串,该选项 将不起作用 
   //"^ab"默认能匹配NSMakeRange(1, 3)]范围上的"babcd"
   //当使用该选项时,则不能匹配 
   NSMatchingWithoutAnchoringBounds = 1 << 4 
};
typedef NS_OPTIONS(NSUInteger, NSMatchingFlags) {
   //还在长时间的匹配中
   NSMatchingProgress               = 1 << 0,  
   //匹配已经完成
   NSMatchingCompleted              = 1 << 1,  
   //当前匹配操作到达搜索范围的末尾     
   NSMatchingHitEnd                 = 1 << 2,  
   //当前匹配项取决于搜索范围末端的位置    
   NSMatchingRequiredEnd            = 1 << 3, 
   //由于内部错误而导致匹配失败而没有检查整个搜索范围   
   NSMatchingInternalError          = 1 << 4     
};
    NSError *error;
    NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:@"[a-z]{3}" 
                                    options:0 error:&error];
    NSString *string = @"abcv1asdf";
    [regular enumerateMatchesInString:string options:NSMatchingReportCompletion 
    range:NSMakeRange(0, string.length) 
    usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) {
        NSLog(@"range = %@ str = %@ flag = %lu", NSStringFromRange(result.range), 
                 [string substringWithRange:result.range], (unsigned long)flags);
    }];
输出:
range = {0, 3} str = abc flag = 0
range = {5, 3} str = asd flag = 0
range = {0, 0} str =  flag = 6

其中的flag = 6实际为NSMatchingCompleted | NSMatchingHitEnd

    NSError *error;
    NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:@"[a-z]{3}" 
                                                        options:0 error:&error];
    NSString *string = @"abcv1asdf";
    NSArray *results = [regular matchesInString:string 
                                options:0 range:NSMakeRange(0, string.length)];
    for (NSTextCheckingResult *object in results) {
        NSLog(@"range = %@ str = %@", NSStringFromRange(object.range), 
                                      [string substringWithRange:object.range]);
    }
    //相当于results.count
    NSInteger count = [regular numberOfMatchesInString:string options:0 
                               range:NSMakeRange(0, string.length)] ;
    //相当于results.firstObject
    NSTextCheckingResult *check = [regular firstMatchInString:string options:0 
                                           range:NSMakeRange(0, string.length)];
    //相当于check.range
    NSRange range = [regular rangeOfFirstMatchInString:string options:0 
                             range:NSMakeRange(0, string.length)];
输出:
range = {0, 3} str = abc
range = {5, 3} str = asd

四、NSRegularExpression的NSReplacement扩展

@interface NSRegularExpression (NSReplacement)

//用templ替换匹配成功的字符串,返回已替换的字符串
//templ 要替换的字符串
//详见例4
- (NSString *)stringByReplacingMatchesInString:(NSString *)string 
              options:(NSMatchingOptions)options range:(NSRange)range 
              withTemplate:(NSString *)templ;
//用templ替换匹配成功的字符串,将在传入的字符串中直接更改,并返回替换的数量
//templ 要替换的字符串
//详见例4
- (NSUInteger)replaceMatchesInString:(NSMutableString *)string 
              options:(NSMatchingOptions)options range:(NSRange)range 
              withTemplate:(NSString *)templ;

//自定义替换,返回传入的templ
//一般传入$0 表示匹配到的字符串 $1表示捕获组的第一个 $2表示第二个
//详见例5
- (NSString *)replacementStringForResult:(NSTextCheckingResult *)result inString:(NSString *)string offset:(NSInteger)offset template:(NSString *)templ;

//将字符串通过\来转义
+ (NSString *)escapedTemplateForString:(NSString *)string;

@end
    NSError *error;
    NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:@"[a-z]{3}" 
                                    options:0 error:&error];
    NSString *string = @"abcv1asdf";
    //用aa替换匹配的字符串 返回替换后的字符串
    NSString *newStr = [regular stringByReplacingMatchesInString:string options:0 
                        range:NSMakeRange(0, string.length) withTemplate:@"aa"];
    NSLog(@"old = %@ ,newStr = %@", string, newStr);
    NSMutableString *muta = string.mutableCopy;
    NSLog(@"old = %@", muta);
    //用bb替换匹配的字符串 返回替换的数量
    NSInteger countt = [regular replaceMatchesInString:muta options:0 
                        range:NSMakeRange(0, muta.length) withTemplate:@"bb"];
    NSLog(@"new = %@ count = %ld", muta, countt);
输出:
old = abcv1asdf
new = bbv1bbf count = 2
    NSRegularExpression *regular1 = [NSRegularExpression regularExpressionWithPattern:@"[a-z]"
                                     options:0 error:nil];
    NSString *string1 = @"abcd";
    NSInteger offset = 0;
    NSMutableString *muta1 = string1.mutableCopy;
    for (NSTextCheckingResult *result in [regular1 matchesInString:muta1 options:0
                                           range:NSMakeRange(0, muta1.length)]) {
        NSRange range = [result range];
        range.location += offset;
        //$0表示匹配到的字符串 $1表示捕获组的第一个 $2表示第二个
        NSString *newStr = [regular replacementStringForResult:result 
                             inString:muta1 offset:offset template:@"$0"];
        NSString *replacement;
        //将单字母变成双字母
        if ([newStr isEqualToString:@"a"]) {
            replacement = @"aa";
        } else if ([newStr isEqualToString:@"b"]) {
            replacement = @"bb";
        } else if ([newStr isEqualToString:@"c"]) {
            replacement = @"cc";
        } else if ([newStr isEqualToString:@"d"]) {
            replacement = @"dd";
        }
        [muta1 replaceCharactersInRange:range withString:replacement];
        //因为替换字符串的长度与原字符串不一致 需要设置偏移量
        offset += ([replacement length] - range.length);
    }
    NSLog(@"%@", muta1);
输出:
aabbccdd

五、子类NSDataDetector的使用

该类中集成了公用的正则表达式,支持查询地址、日期、链接,号码等

@interface NSDataDetector : NSRegularExpression

//通过检查类型来初始化
// checkingTypes 详见说明4
//详见例6
+ (nullable NSDataDetector *)dataDetectorWithTypes:(NSTextCheckingTypes)checkingTypes 
                                             error:(NSError **)error;
//实例初始化方法
- (nullable instancetype)initWithTypes:(NSTextCheckingTypes)checkingTypes 
                                 error:(NSError **)error;
//类型 只读
@property (readonly) NSTextCheckingTypes checkingTypes;

@end
NS_ENUM(NSTextCheckingTypes) {
    //系统保留前32种类型
    NSTextCheckingAllSystemTypes    = 0xffffffffULL,     
    //其余可供用户自定义的类型   
    NSTextCheckingAllCustomTypes    = 0xffffffffULL << 32,  
    //所有类型
    NSTextCheckingAllTypes          = (NSTextCheckingAllSystemTypes | NSTextCheckingAllCustomTypes)
};
前32种类型为下面的选项
typedef NS_OPTIONS(uint64_t, NSTextCheckingType) {    
    //语言辩识
    NSTextCheckingTypeOrthography           = 1ULL << 0,       
    //拼写检查     
    NSTextCheckingTypeSpelling              = 1ULL << 1,           
    //语法检查
    NSTextCheckingTypeGrammar               = 1ULL << 2,            
    //日期时间检测
    NSTextCheckingTypeDate                  = 1ULL << 3,        
    //地址检测
    NSTextCheckingTypeAddress               = 1ULL << 4,          
    //链接检测
    NSTextCheckingTypeLink                  = 1ULL << 5,           
    //智能引用
    NSTextCheckingTypeQuote                 = 1ULL << 6,           
    //智能破折号
    NSTextCheckingTypeDash                  = 1ULL << 7,          
    //固定替换
    NSTextCheckingTypeReplacement           = 1ULL << 8,          
    //自动改正
    NSTextCheckingTypeCorrection            = 1ULL << 9,           
    //自定义正则表达式
    NSTextCheckingTypeRegularExpression   = 1ULL << 10,       
    //电话号码检测    
    NSTextCheckingTypePhoneNumber         = 1ULL << 11,          
    //过境(例如航班)信息检测
    NSTextCheckingTypeTransitInformation
};
    NSDataDetector *detactor = [NSDataDetector dataDetectorWithTypes:NSTextCheckingAllSystemTypes error:nil];
    NSString *detaStr = @"我叫百度,我的主页是https://www.baidu.com,我的手机号为13812345678";
    NSArray *detaResults  = [detactor matchesInString:detaStr options:0 
                                      range:NSMakeRange(0, detaStr.length)];
    NSLog(@"%@", detaResults);
输出:
(
    "<NSLinkCheckingResult: 0x600003781220>{10, 21}{https://www.baidu.com}",
    "<NSPhoneNumberCheckingResult: 0x60000390ddd0>{38, 11}{13812345678}"
)

匹配出两个字符串,一个是链接,一个是号码。

上一篇下一篇

猜你喜欢

热点阅读