美文网首页iOS开发常用知识点
iOS NSPredicate和NSRegularExpress

iOS NSPredicate和NSRegularExpress

作者: 明若晴空 | 来源:发表于2018-08-31 19:05 被阅读129次

NSPredicate

Predicate:断言,谓语,术语的意思。

定义一个逻辑条件,用来在内存过滤或者获取时,限定搜索的条件。

Predicates表示一个可以用来过滤对象集合的条件。通常,我们可以从 NSComparisonPredicate, NSCompoundPredicate, 和 NSExpression的实例直接创建predicates,但是,我们也可以从格式化的string来创建predicates,这个格式化的string可以被NSPredicate的类方法解析。

predicates 格式化string的例子包括:

  • 简单的比较,如 grade == "7” , firstName like “Shaffiq"
  • 不区分大小写[c]与不区分重音符号[d]的模糊匹配,如 name contains[cd] "itroen"
  • 逻辑操作,如 (firstName like "Mark”) 或 (lastName like "Adderley")
  • 时间范围的约束,如 date between {YESTERDAY,TOMORROW}
  • 相关条件,如 group.name like "work*"
  • 集合运算,如 @sum.items.price < 1000

完整的语句参考地址:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html#//apple_ref/doc/uid/TP40001789

我们也可以通过 evaluateWithObject:substitutionVariables: 方法创建一个包含变量的predicates,这样,predicate就可以在运行时替代具体的值之前预定义。

1、创建predicate的方法:

  • + predicateWithFormat:
  • 通过创建一个新的string并解析,来创建并返回一个新的predicate;
  • + predicateWithFormat:argumentArray:
  • 通过给定数组中的值来替代格式化string并解析,来实例化一个predicate;
  • + predicateWithFormat:arguments:
  • 通过给定参数的值来替代格式化string并解析,来实例化一个predicate;
  • - predicateWithSubstitutionVariables:
  • 返回一个predicate的copy,新的copy对象中的变量将会被给定字典中特定的值替代;
  • + predicateWithValue:
  • 对给定的bool值进行评估来创建并返回predicate;
  • + predicateWithBlock:
  • 通过特定的block对象和字典的评估来实例化一个predicate;
  • + predicateFromMetadataQueryString:
  • 通过一个元数据查询字符串来实例化一个predicate;

2、评估一个predicate

  • - evaluateWithObject:
  • 返回一个bool值,表明特定的对象和predicate指定的条件是否匹配;
  • - evaluateWithObject:substitutionVariables:
  • 返回一个bool值,表明特定的对象和predicate在替代了给定字典中的值后指定的条件是否匹配;
  • - allowEvaluation
  • 强制安全解码的predicate允许被评估。当一个使用 NSSecureCoding编码的predicate对象在安全解码时,是不能被评估的。因为评估一个从存档中取出的predicate是有潜在风险的。在激活评估之前,我们应该证实 key paths, selectors,和其他细节来确保没有错误或恶意代码被执行。一旦我们验证了predicate,我们就可以通过调用allowEvaluation来激活接收器来评估。
    3、获取一个字符串表达式
  • predicateFormat:NSPredicate的只读属性;

NSRegularExpression

一个不可变的表示形式,可用于Unicode string的编译正则表达式。

NSRegularExpression的基本匹配方法是一个Block迭代方法,可允许客户端提供一个Block对象,来当正则表达式匹配上目标字符的一部分时,该Block块被调用。还有其他一些方便的方法,可以返回把所有匹配结果的数组,匹配的总数,第一个匹配结果,第一个匹配的range。

单个的匹配结果,用 NSTextCheckingResult类的实例来表示,它携带了关于全部匹配范围(range属性),每个匹配结果的范围( rangeAtIndex:方法)等等信息。对于基本的 NSRegularExpression对象,匹配结果是 NSTextCheckingTypeRegularExpression,但是子类或许可以使用其他类型。

NSRegularExpression的使用示例

下面是NSRegularExpression类的一系列示例,这些例子使用 \b(a|b)(c|d)\b的正则表达式来作为他们的正则表达式。

这段代码创建了一个正则表达式来匹配两个字符的单词,其首字母是“a”或者“b”,第二个字母是“c”或者“d”。指定NSRegularExpressionCaseInsensitive意味着,匹配是不区分大小写的,所以它也匹配到“BC”,“aD”等等,或者相同的小写。

NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\b(a|b)(c|d)\\b"
                                                                       options:NSRegularExpressionCaseInsensitive
                                                                         error:&error];

numberOfMatchesInString:options:range: 方法提供了一个简单的机制来计算给定字符串范围内的匹配结果个数。

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

如果你只对第一个匹配结果的范围感兴趣,那就可以使用 rangeOfFirstMatchInString:options:range: 方法。一些正则表达式可以成功的匹配0长度的范围,因此和 {NSNotFound, 0} 的range进行对比,是检验是否有匹配结果的最可靠的方法。

示例中的正则表达式包含了两组捕获条件,分别对应两组圆括号中的内容,一个是首字母,一个是第二个字母。如果你不仅仅关注整个匹配范围,还想获取对应给定的匹配结果的 NSTextCheckingResult对象。这个 NSTextCheckingResult对象通过range属性提供了整个匹配范围的信息,还通过rangeAtIndex方法提供了每个匹配结果的范围信息。
第一个匹配结果通过 [result rangeAtIndex:1]可得到,第二个匹配结果通过 [result rangeAtIndex:2]可得到。 [result rangeAtIndex:0]相当于 [result range]。

如果result返回non-nil,那么[result range]将是一个有效的范围,因此,和{NSNotFound, 0} 的range进行对比是没有必要的。但是,对于正则表达式,匹配结果可能参加,也可能不参加给定的匹配条件,如果匹配结果没有参加给定匹配,那么 [result rangeAtIndex:idx] 将会返回 {NSNotFound, 0}。

NSRange rangeOfFirstMatch = [regex rangeOfFirstMatchInString:string options:0 range:NSMakeRange(0, [string length])];
if (!NSEqualRanges(rangeOfFirstMatch, NSMakeRange(NSNotFound, 0))) {
    NSString *substringForFirstMatch = [string substringWithRange:rangeOfFirstMatch];
}

matchesInString:options:range: 会返回所有的匹配结果。

NSArray *matches = [regex matchesInString:string
                                  options:0
                                    range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matches) {
     NSRange matchRange = [match range];
     NSRange firstHalfRange = [match rangeAtIndex:1];
     NSRange secondHalfRange = [match rangeAtIndex:2];
}

firstMatchInString:options:range: 方法和matchesInString:options:range:方法类似,只是返回的是第一个匹配结果。

NSTextCheckingResult *match = [regex firstMatchInString:string
                                                options:0
                                                  range:NSMakeRange(0, [string length])];
if (match) {
    NSRange matchRange = [match range];
    NSRange firstHalfRange = [match rangeAtIndex:1];
    NSRange secondHalfRange = [match rangeAtIndex:2];
 }

enumerateMatchesInString:options:range:usingBlock:这个Block枚举方法,是NSRegularExpression的匹配方法中最普通和灵活的。我们可以用它循环迭代字符串中的匹配结果,执行块中指定的任意操作,也可以在需要的时候终止。下面的例子中,循环迭代是在获取到一定数量的匹配结果后终止的。

如果没有特殊项NSMatchingReportProgress ,也没有NSMatchingReportCompletion ,那么Block的result参数保证是非nil的,也就是保证range是有效的。

__block NSUInteger count = 0;
[regex enumerateMatchesInString:string options:0 range:NSMakeRange(0, [string length]) usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){
     NSRange matchRange = [match range];
     NSRange firstHalfRange = [match rangeAtIndex:1];
     NSRange secondHalfRange = [match rangeAtIndex:2];
     if (++count >= 100) *stop = YES;
}];

NSRegularExpression也提供了一些简单的方法来执行查询并替换的操作。下面的例子返回一个被修改的copy,但是又一个相应的方法来修改一个可更改的字符串。模板指定用于替换匹配结果的内容,0代表整个匹配范围的内容,1代表第一个匹配范围的内容,等等。在这个例子中,模板将单词中的两个字母颠倒:

NSString *modifiedString = [regex stringByReplacingMatchesInString:string
                                                           options:0
                                                             range:NSMakeRange(0, [string length])
                                                      withTemplate:@"$2$1”];

并发与线程安全

NSRegularExpression是不可更改的,线程安全的。因此,单例被用在多线程的匹配操作中。然而,在操作过程中,不管事在另一个线程中,还是在迭代的Block,字符串都不应该被改变。

正则表达式语句

下表描述了用来在字符串中进行模式匹配的正则表达式中用到的字符表达式,指定多少次模式匹配和额外的匹配约束的模式运算符,最后一个表指定了正则表达式中包含的标志位,可指定多行搜索行为(这些标志位也可以通过 NSRegularExpressionOptions来指定)。

正则表达式元字符

表1中描述了用来匹配字符的字符序列

Character Expression Description
\a 匹配响铃字符, \u0007
\A 匹配字符串开头。与^不同,\A不会换行匹配,也就是不支持多行匹配
\b, outside of a [Set] 匹配当前位置是否是单词的边界。边界出现在单词字符(\w语言元素)和非单词字符(\W语言元素)之间的边界上。单词字符包括字母数字字符和下划线。
\b, within a [Set] 匹配退格键, \u0008.
\B 匹配不得出现在\b边界上
\cX匹配由X指定的控制字符
\d 匹配一个数字字符,[0-9]
\D 匹配一个非数字字符,与\d相反
\e 匹配转义字符, \u001B.
\E 终止\Q启动的(将元字符视为非元字符)的功能.
\f 匹配换页符, \u000C.
\G 匹配必须出现在上一个匹配结束的地方
\n 匹配换行符, \u000A.
\N{UNICODE CHARACTER NAME} 匹配命名字符
\p{UNICODE PROPERTY NAME} 匹配指定的Unicode通用类别或命名块中的任何单个字符
\P{UNICODE PROPERTY NAME} 匹配不在指定的Unicode通用类别或命名块中的任何单个字符
\Q 将元字符视为非元字符,直到碰到\E
\r 匹配回车符, \u000D.
\s 匹配白空格字符. 白空格定义为 [\t\n\f\r\p{Z}].
\S 匹配非白空格字符
\t 匹配水平制表符, \u0009.
\uhhhh 使用十六进制匹配字符
\Uhhhhhhhh 使用十六进制匹配字符。必须是精确的8位16进制数
\w 匹配单词字符,包括字母字符,数字,下划线
\W 匹配非单词字符
\x{hhhh} 匹配0xhhhh的字符,从1到6位16进制数字被提供
\xhh 匹配0xhh的字符,从1到2位16进制数字被提供
\X 匹配字形聚类
\Z 匹配是否是结尾处的位置,并且在字符串末尾的\n之前。
\z 匹配是否是结尾处的位置
\n 向后引用,匹配第n个匹配结果。n必须1 < n < 匹配结果的总数.
\0ooo 匹配八进制字符。Match an Octal character. ooo is from one to three octal digits. 0377 is the largest allowed Octal character. The leading zero is required; it distinguishes Octal constants from back references.
[pattern] 匹配模式中的任意一个字符.
. 匹配任何字符
^ 匹配行首
$ 匹配行尾
标记下一个字符为特殊字符。下列字符必须被标记为转义字符 * ? + [ ( ) { } ^ $ \ . /

正则表达式运算符

Character Expression Description
| 逻辑“或”运算. A B 匹配 A 或 B.
* 匹配表达式0次或尽可能多次.
+ 匹配表达式1次或尽可能多次.
? 匹配0次或1次.
{n} 匹配精确的n次.
{n,} 匹配至少n次. 尽可能匹配多次.
{n,m} 匹配n到m次。 尽可能匹配多次,但不能超过m次.
*? 匹配0次或多次。
+? 匹配1次或多次.
?? 匹配0次或1次.
{n}? 精确匹配n次.
{n,}? 至少匹配n次,但次数尽可能少
{n,m}? 匹配n~m次,但次数尽可能少
*+ 匹配0次或多次。当第一次遇到时,尽可能多地匹配。即使整个匹配失败,也不要重试。
++ 匹配1次或多次
?+ 匹配0次或多次.
{n}+ 精确匹配n次
{n,}+ 匹配至少n次.
{n,m}+ 匹配n~m次.
(...) 匹配圆括号。匹配后,匹配圆括号的子表达式的输入范围是可用的。
(?:...) 匹配非圆括号
(?>...) 原子匹配圆括号的子表达式
(?# ... ) 无格式注释,…为注释内容.
(?= ... ) 前瞻断言。
(?! ... ) 否定的前瞻断言
(?<= ... ) Look-behind 断言
(?<! ... ) 否定的Look-behind 断言
(?ismwx-ismwx:... ) 标志位设置
(?ismwx-ismwx) 标志位设置

模板匹配格式

NSRegularExpression类使用模板匹配的技巧对不可变和可变字符串提供了查找并替代的方法。
下表描述了模板匹配的语法:

模板 描述
$n 捕获组n的text将会被替换为n,n必须大于0且小于等于捕获组的数目。没有数字跟随的没有特殊含义,它将在替换文本中,只作为$。

\把字符作为字面含义,不代表任何特殊意义。替换文本中的\只用于$和\,但是也可以用于没有不良影响的其他字符。

替代字符被当做一个模板,0代表匹配范围内的内容都被替换。1代表第一个捕获组的内容被替换。超出捕获组总数最大值的将被视为普通字符,没有数字跟随的。反斜杠对和\转义。

性能

NSRegularExpression是一个非确定有限自动匹配引擎。基于此,包含*或者+运算符的复杂正则表达式模板在匹配时,性能比较差,甚至匹配失败。

创建正则表达式

  • + regularExpressionWithPattern:options:error:
    使用特定的正则表达式模板和options创建NSRegularExpression实例。
    - initWithPattern:options:error:
    使用特定的正则表达式模板和options返回NSRegularExpression实例。

获取整个表达式和options

  • pattern: 返回正则表达式模板
  • options

numberOfCaptureGroups
返回正则表达式的捕获组总数

使用正则表达式搜索字符串

  • - numberOfMatchesInString:options:range:

返回指定范围字符内的正则匹配数量。

  • - enumerateMatchesInString:options:range:usingBlock:

使用Block来处理正则表达匹配结果来枚举字符串。

  • - matchesInString:options:range:

返回返回包含字符中的所有正则匹配结果的数组

  • - firstMatchInString:options:range:

返回返回包含字符中的第一个正则匹配结果

  • - rangeOfFirstMatchInString:options:range:

返回返回包含字符中的第一个正则匹配结果的范围。

使用正则表示替代字符串

  • - replaceMatchesInString:options:range:withTemplate:

使用模板字符串替换可变字符串内匹配的正则表达式

  • - stringByReplacingMatchesInString:options:range:withTemplate:

返回一个包含使用模板字符串替换匹配正则表达式的新字符串

转义字符串中的字符

  • + escapedTemplateForString:

返回增加了必要的反斜杠转义来保护字符的匹配模板元字符的一个模板字符串

  • + escapedPatternForString:

返回增加了必要的反斜杠转义来保护字符的匹配模板元字符的一个字符串

自定义替换功能

  • - replacementStringForResult:inString:offset:template:

用来对单个结果执行模板替换来实现他们自己的替换功能

约束

  • NSRegularExpressionOptions

这些约束定义了正则表达式的选项,这些约束通过属性regularExpressionWithPattern:options:error:和 initWithPattern:options:error:来使用,.

  • NSMatchingFlags

通过匹配进度,完成,失败的Block来设置。通过方法enumerateMatchesInString:options:range:usingBlock:来使用

  • NSMatchingOptions

匹配选项约束指定了表达式的报告,完成和匹配规则等匹配方法。这些约束在所有搜索,替代使用正则表达式的地方使用。

相关文章

网友评论

    本文标题:iOS NSPredicate和NSRegularExpress

    本文链接:https://www.haomeiwen.com/subject/njeewftx.html