IOS NSRegularExpression 解析正则表达式

来源:互联网 发布:淘宝正品化妆品店 编辑:程序博客网 时间:2024/05/28 05:19

iOS 中可以通过 NSPredicate 来处理正则表达式。相关资料如下:

NSPredicate 苹果官方文档:
http://developer.apple.com/documentation/Cocoa/Conceptual/Predicates/predicates.html

Predicate format strings:
http://developer.apple.com/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html

ICU 正则表达式规则:
http://www.icu-project.org/userguide/regexp.html

 

在 iOS 中,我们使用 NSPredicate 的字符串比较功能来进行正则表达式处理,其比较关键字为:MATCHES

 

下面,列举一个匹配6-15个由字母/数字组成的字符串的正则表达式,来看看 NSPredicate 的具体使用:

    NSString * regex        = @"(^[A-Za-z0-9]{6,15}$)";
NSPredicate * pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
BOOL isMatch = [pred evaluateWithObject:@"123456ABCde"];

 





初始化一个   NSRegularExpression 对象   注:_str是要匹配的字符串

NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"http://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?" options:NSRegularExpressionCaseInsensitive error:nil];


获得所有匹配了表达式的字符串。

    NSArray *array =    nil;

    array = [regex matchesInString:_str options:0 range:NSMakeRange(0, [_str length])];
    NSString *str1 = nil;
    for (NSTextCheckingResult* b in array)

    {

         str1 是每个和表达式匹配好的字符串。


        str1 = [_str substringWithRange:b.range];
        NSLog(@" str 1 is %@",str1);


    }

获得匹配的字符串的个数

NSUInteger numberOfMatches = [regex numberOfMatchesInString:_str options:0 range:NSMakeRange(0, [_str length])];

替换匹配的字符串  $0很重要 $0不行的话 $1依此类推 打印了看结果


NSString *modifiedString = [regex stringByReplacingMatchesInString:_str
                                                               options:0
                                                                 range:NSMakeRange(0, [_str length])
                                                          withTemplate:@"<a href=\"$0\">$0</a>"];
NSLog(@"######## the modified string is %@",modifiedString);




2. 

NSString *regExStr =@"<input type='hidden' id='([G|U]{1})(\\d+)' value='(.*?)'>";

                

               NSError *error = NULL;

                

                NSRegularExpression *regex = [NSRegularExpressionregularExpressionWithPattern:regExStroptions:NSRegularExpressionCaseInsensitiveerror:&error];

                

                [regexenumerateMatchesInString:addressBookString options:0 range:NSMakeRange(0, [addressBookStringlength]) usingBlock:^(NSTextCheckingResult *regResult,NSMatchingFlags flags, BOOL*stop) {

                    

                   NSString *type = [NSStringstringWithString:[addressBookString substringWithRange:[regResult rangeAtIndex:1]]];

                   NSString *nameID = [NSStringstringWithString:[addressBookStringsubstringWithRange:[regResult rangeAtIndex:2]]];

                   NSString *name = [NSStringstringWithString:[addressBookString substringWithRange:[regResult rangeAtIndex:3]]];

                    

                   if([type isEqualToString:@"G"]){

                       AddressBookNode *addressBookNode = [[AddressBookNodealloc]init];

                        addressBookNode.isDirectory =TRUE;

                        addressBookNode.nodeLevel =1;

                        addressBookNode.nodeName = name;

                        addressBookNode.nodeID = nameID;

                        [addressBookaddChild:addressBookNode];


                        

                    }else{

                       AddressBookNode *addressBookNode = [[AddressBookNodealloc]init];

                        addressBookNode.isDirectory =FALSE;

                        addressBookNode.nodeLevel =1;

                        addressBookNode.nodeName = name;

                        addressBookNode.nodeID = nameID;

                        [addressBookaddChild:addressBookNode];

                        

                    }

                    

                }];



3. 

char *utf8CString = "test;;; test2 what are you doing, now?";
06    NSString *regexString = @";";
07    NSString *sourceString = [NSString stringWithUTF8String:utf8CString];  
08    NSString *resultString = [sourceString stringByReplacingOccurrencesOfRegex:regexString withString:@"_"];
09     
10    NSLog(@"sourceString: \"%@\"", sourceString);
11    NSLog(@"resultString: \"%@\"", resultString);  
12     
13    char *utf8CString1 = "Copyright \xC2\xA9 \xE2\x89\x85 2008";
14    NSString *regexString1 = @"Copyright (.*) (\\d+)";  
15    NSString *sourceString1 = [NSString stringWithUTF8String:utf8CString1];
16    NSString *resultString1 = [sourceString1 stringByMatching:regexString1 capture:1L];
17     
18    NSLog(@"sourceString: \"%@\"", sourceString1);
19    NSLog(@"resultString: \"%@\"", resultString1);
20     
21    char *utf8CString2 = "One\t Two \tThree ";
22    NSString *source = [NSString stringWithUTF8String:utf8CString2];
23    NSString *result = [source stringByReplacingOccurrencesOfRegex:@"\\s+"withString:@" "];
24     
25    NSLog(source);
26    NSLog(result);
27     
28    NSString *source1 = @"Test;12;Y";
29    NSArray *columns = [source1 componentsSeparatedByRegex:@";\\s*"];
30     
31    NSLog([columns description]);
32     
33    NSString *source2 = @"<foo no=\"12\">Name</foo>";
34    NSString *regex2 = @"<foo no=\"(.+?)\">(.*?)</foo>";
35    int no = [[source2 stringByMatching:regex2 capture:1] intValue];
36    NSString *data = [source2 stringByMatching:regex2 capture:2];
37     
38    NSLog(@"no: %d data: %@", no, data);

在 iOS 开发中要用正则表达式的话,至少有三种选择:

1. 系统自带的  NSString 和 NSMutableString 相关的方法
2. RegexKit Framework - http://regexkit.sourceforge.net
3. RegexKitLite - http://regexkit.sourceforge.net/RegexKitLite/

NSString 和 NSMutableString 里像

1
2
3
- (NSRange)rangeOfString:(NSString*)aString options:(NSStringCompareOptions)mask;
- (NSUInteger)replaceOccurrencesOfString:(NSString*)target withString:(NSString*)replacement
                                 options:(NSStringCompareOptions)options range:(NSRange)searchRange;

带有 NSStringCompareOptions 参数的方法就可以支持正则表达式,只要对于 NSStringCompareOptions 参数取值中含有 NSRegularExpressionSearch 这个 Mask 值即可。

RegexKit Framework 用的是 PCRE(Perl Compatible Regular Expressions) 库,可能是我们熟悉正则表达式语法,但需要引入 PCRE 静态库。

RegexKitLite,看链接它与 RegexKit Framework 出自一家,但它用的是 Mac 自带的 ICU(International Components for Unicode) 库,所以语法上与 RegexKit Framework 是不一样的,且引入它也较简单。

只要下载到文件 RegexKitLite-4.0.tar.bz2,解压出其中的 RegexKitLite.h 和 RegexKitLite.m 两文件加到项目中来,再就记得加上系统自带的 libicucore.dylib 库就行。RegexKitLite 所有的方法也是对 NSString 和 NSMutableString 两个类的扩展方法,典型的方法:

1
2
3
4
5
- (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString*)regex;
- (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString*)regex inRange:(NSRange)range;
- (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString*)regex withString:(NSString*)
- (NSArray*)RKL_METHOD_PREPEND(captureComponentsMatchedByRegex):(NSString*)regex;
............................................

真要说 RegexKitLite 的用法,也就又回到了正则表达式的写法,没什么可说的,只要参考:http://regexkit.sourceforge.net/RegexKitLite/,里面也有所有的扩展方法列表。

因此,这里只说一个如何进行不区分大小写的匹配,沿袭以往的经验,要么向 JS 那样 /abc/i,要么就是加上不区分大小写的标识参数,如:

1
2
- (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString*)regex options:(RKLRegexOptions)options
                                     inRange:(NSRange)range error:(NSError**)error;

中的 (RKLRegexOptions)options 参数,可以支持:

RKLNoOptions, RKLCaseless, RKLComments, RKLDotAll, RKLMultiline, RKLUnicodeWordBoundarie

这个组合,只要标识上 RKLCaseless。然而你也许发现了如果不区分大小写的匹配,调用方法只是:

1
- (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString*)regex;

就因为要支持大小写不敏感而必须用另一个参数多几个的重载方法,要是想要应用 replaceOccurrencesOfRegex 方法,大小写不敏感比不敏感的方法版本参数多的更多,实际并不用关心那些多余的参数,甚是不便。

那么能不能像 JS 的正则表达式那样把约束标识写在正则表达式里呢,可以的,请试一下:

1
2
3
4
5
6
7
8
if([@"Unmi"isMatchedByRegex:@"(?i)uNmI"]){
    NSLog(@"Matched");
}
 
//下面的代码一样的效果
if([@"Unmi"isMatchedByRegex:@"(?i:uNmI)"]){
    NSLog(@"Matched");
}

会输出 Matched,匹配成功,关键就是表达式中的 (?i)Xxx 或者 (?i:Xxx) 表明这个表达式不区分大小写,可以查看下这个帮助原文:


Options for controlling the behavior of a regular expression pattern can be controlled in two ways. When the method supports it, options may specified by combiningRKLRegexOptions flags with the C bitwise OR operator. For example:

matchedRange = [aString rangeOfRegex:@"^(blue|red)$" options:(RKLCaseless | RKLMultiline) inRange:range error:NULL];

The other way is to specify the options within the regular expression itself, of which there are two ways. The first specifies the options for everything following it, and the other sets the options on a per capture group basis. Options are either enabled, or following a -, disabled. The syntax for both is nearly identical:

OptionExampleDescription(?ixsmw-ixsmw)…(?i)…Enables the RKLCaseless option for everything that follows it. Useful at the beginning of a regular expression to set the desired options.(?ixsmw-ixsmw:…)(?iw-m:…)Enables the RKLCaseless and RKLUnicodeWordBoundaries options and disables RKLMultiline for the capture group enclosed by the parenthesis.

The following table lists the regular expression pattern option character and its corresponding RKLRegexOptions flag:

CharacterOptioniRKLCaselessxRKLCommentssRKLDotAllmRKLMultilinewRKLUnicodeWordBoundaries

上面就是说对正则表达式的控件可以有两种选择,用 RKLRegexOptions 标识,或在表达式中用 (?..) 的写法。第二种选择又有两种写法,一种是 (?i)...  和 (?i:...)。问号后支持 i、x、s、m 和 w 五个标识,各自的意义看上面的表格,在标识前加个减号 - 表示去除该特性。

附上一些常用的 ICU 格式正则表达式:

Network and URL

DescriptionRegexHTTP\bhttps?://[a-zA-Z0-9\-.]+(?:(?:/[a-zA-Z0-9\-._?,'+\&%$=~*!():@\\]*)+)?HTTP\b(https?)://([a-zA-Z0-9\-.]+)((?:/[a-zA-Z0-9\-._?,'+\&%$=~*!():@\\]*)+)?HTTP\b(https?)://(?:(\S+?)(?::(\S+?))?@)?([a-zA-Z0-9\-.]+)(?::(\d+))?((?:/[a-zA-Z0-9\-._?,'+\&%$=~*!():@\\]*)+)?E-Mail\b([a-zA-Z0-9%_.+\-]+)@([a-zA-Z0-9.\-]+?\.[a-zA-Z]{2,6})\bHostname\b(?:[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}?[a-zA-Z0-9]\.)+[a-zA-Z]{2,6}\bIP\b(?:\d{1,3}\.){3}\d{1,3}\bIP with Optional Netmask\b((?:\d{1,3}\.){3}\d{1,3})(?:/(\d{1,2}))?\bIP or Hostname\b(?:(?:\d{1,3}\.){3}\d{1,3}|(?:[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}?[a-zA-Z0-9]\.)+[a-zA-Z]{2,6})\b

上面的正则表达式实际书写时需把一个反斜杠替换成两个反斜杠,如匹配 E-Mail 时要写成

1
2
3
4
5
NSString*regex = @"\\b([a-zA-Z0-9%_.+\\-]+)@([a-zA-Z0-9.\\-]+?\\.[a-zA-Z]{2,6})\\b";
NSLog(@"Regex: %@", regex);
if([@"unmi@scalau.com"isMatchedByRegex:regex]){
    NSLog(@"Valid email address");
}

上面的代码输出:

Regex: \b([a-zA-Z0-9%_.+\-]+)@([a-zA-Z0-9.\-]+?\.[a-zA-Z]{2,6})\b
Valid email address

这和 Java 的正则表达式一样,也就是要写成 NSLog 输出的样子,也就是转义的转义,如果是 \- 或 \. 编译时会提示:

Lexical or Preprocessor Issue Unknown escape sequence "\."
Lexical or Preprocessor Issue Unknown escape sequence "\-"

但执行时不会报错,只是匹配不成功.

记住,RegexKitLite 的完全帮助手册尽在:http://regexkit.sourceforge.net/RegexKitLite/


0 0
原创粉丝点击