NSRegularExpression的使用

版本:iOS13.7

一、簡介

NSRegularExpression是利用正則表達式匹配字符串的類,初始化成功后不可更改。
正則表達式的具體語法可查看iOS正則表達式語法全集。使用時若有\b這類字符,需要傳入\\b,如"aa\\b"表示查詢在在邊界的aa字符串,"aa\b"表示的是查詢aa\b這個字符串。

二、NSRegularExpression的api

@interface NSRegularExpression : NSObject <NSCopying, NSSecureCoding> 

//通過模式和選頂創(chuàng)建正則表達式
//若模式無效,則返回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;
//返回正則表達式的捕獲組數(shù)量 只讀
@property (readonly) NSUInteger numberOfCaptureGroups;

//將字符串通過\來轉(zhuǎn)義
+ (NSString *)escapedPatternForString:(NSString *)string;

@end
  • 說明1
    若不想指定選項,可以傳入0
typedef NS_OPTIONS(NSUInteger, NSRegularExpressionOptions) {
   //忽略大小寫 "AA"相當(dāng)于"aa"
   NSRegularExpressionCaseInsensitive             = 1 << 0,
   //忽略空格和#后面的注釋 "A B#AA"相當(dāng)于"AB"
   NSRegularExpressionAllowCommentsAndWhitespace  = 1 << 1,    
   //將整個模式視為文字字符串 "AA\\b"其中的\\b不會當(dāng)成匹配邊界,而是字符串
   NSRegularExpressionIgnoreMetacharacters        = 1 << 2,   
   //允許.匹配任何字符,包括行分隔符。"a.b"可以匹配"a\nb"
   NSRegularExpressionDotMatchesLineSeparators    = 1 << 3,     
   //允許^和$匹配行的開頭和結(jié)尾(這個好像是一直生效的)
   NSRegularExpressionAnchorsMatchLines           = 1 << 4,    
   //僅將\n視為行分隔符,否則,將使用所有標(biāo)準(zhǔn)行分隔符
   NSRegularExpressionUseUnixLineSeparators       = 1 << 5,     
   //使用Unicode TR#29指定單詞邊界,否則,使用傳統(tǒng)的正則表達式單詞邊界
   NSRegularExpressionUseUnicodeWordBoundaries    = 1 << 6   
};

三、NSRegularExpression的NSMatching擴展

@interface NSRegularExpression (NSMatching)

//匹配字符串,并在成功匹配時回調(diào)一次block
//string 需要匹配的字符串
//options 匹配選項 詳見說明2
//range 需要匹配的字符串的范圍
//回調(diào)block result 匹配的結(jié)果,若result.range不為{0, 0}則表示匹配成功
//flags 當(dāng)前狀態(tài) 詳見說明3
//stop 停止符 當(dāng)設(shè)為YES時,將停止匹配。
//詳見例2
- (void)enumerateMatchesInString:(NSString *)string 
        options:(NSMatchingOptions)options range:(NSRange)range 
        usingBlock:(void (NS_NOESCAPE ^)(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL *stop))block;

//匹配字符串,返回匹配結(jié)果的數(shù)組
//詳見例3
- (NSArray<NSTextCheckingResult *> *)matchesInString:(NSString *)string 
            options:(NSMatchingOptions)options range:(NSRange)range;
//匹配字符串,返回匹配結(jié)果的數(shù)量
//詳見例3
- (NSUInteger)numberOfMatchesInString:(NSString *)string 
              options:(NSMatchingOptions)options range:(NSRange)range;
//匹配字符串,返回第一個匹配結(jié)果
//詳見例3
- (nullable NSTextCheckingResult *)firstMatchInString:(NSString *)string 
             options:(NSMatchingOptions)options range:(NSRange)range;
//匹配字符串,返回第一個匹配結(jié)果的范圍
//詳見例3
- (NSRange)rangeOfFirstMatchInString:(NSString *)string 
             options:(NSMatchingOptions)options range:(NSRange)range;

@end
  • 說明2
    若不想指定,則傳入0,此時只有成功匹配時才會回調(diào)。
typedef NS_OPTIONS(NSUInteger, NSMatchingOptions) {
   //在長時間的匹配操作期間,定期回調(diào)一次。
   NSMatchingReportProgress         = 1 << 0,       
   //當(dāng)匹配完成時,回調(diào)一次。
   NSMatchingReportCompletion       = 1 << 1,
   //只能匹配查詢范圍開始處的字符串  "aa"只能匹配"aabcd",而不能匹配"baabcd"       
   NSMatchingAnchored               = 1 << 2,      
   //允許匹配超出搜索范圍的范圍,例如文字邊界檢測,前瞻等。如果搜索范圍包含整個字符串,該選項將不起作用 
   NSMatchingWithTransparentBounds  = 1 << 3,      
   //防止^和$自動匹配搜索范圍的開始和結(jié)束,如果搜索范圍包含整個字符串,該選項 將不起作用 
   //"^ab"默認(rèn)能匹配NSMakeRange(1, 3)]范圍上的"babcd"
   //當(dāng)使用該選項時,則不能匹配 
   NSMatchingWithoutAnchoringBounds = 1 << 4 
};
  • 說明3
typedef NS_OPTIONS(NSUInteger, NSMatchingFlags) {
   //還在長時間的匹配中
   NSMatchingProgress               = 1 << 0,  
   //匹配已經(jīng)完成
   NSMatchingCompleted              = 1 << 1,  
   //當(dāng)前匹配操作到達搜索范圍的末尾     
   NSMatchingHitEnd                 = 1 << 2,  
   //當(dāng)前匹配項取決于搜索范圍末端的位置    
   NSMatchingRequiredEnd            = 1 << 3, 
   //由于內(nèi)部錯誤而導(dǎo)致匹配失敗而沒有檢查整個搜索范圍   
   NSMatchingInternalError          = 1 << 4     
};
  • 例2
    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

  • 例3
    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]);
    }
    //相當(dāng)于results.count
    NSInteger count = [regular numberOfMatchesInString:string options:0 
                               range:NSMakeRange(0, string.length)] ;
    //相當(dāng)于results.firstObject
    NSTextCheckingResult *check = [regular firstMatchInString:string options:0 
                                           range:NSMakeRange(0, string.length)];
    //相當(dāng)于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替換匹配成功的字符串,將在傳入的字符串中直接更改,并返回替換的數(shù)量
//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;

//將字符串通過\來轉(zhuǎn)義
+ (NSString *)escapedTemplateForString:(NSString *)string;

@end
  • 例4
    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替換匹配的字符串 返回替換的數(shù)量
    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
  • 例5
    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];
        //因為替換字符串的長度與原字符串不一致 需要設(shè)置偏移量
        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
  • 說明4
NS_ENUM(NSTextCheckingTypes) {
    //系統(tǒng)保留前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
};
  • 例6
    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}"
)

匹配出兩個字符串,一個是鏈接,一個是號碼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容