Objective-C的正则表达式
一、工具
- 在线匹配工具 菜鸟工具
- 安装包工具 regexBuddy_Mac
- 图形化展示工具regulex
二、正则
2.1 使用场景
- 用来批量提取或替换有规律的字符串;
- 在高级文本编辑器中使用;
- 在各类办公软件(office等)中使用;
- 检测用户的输入是否合法;
- 在各种开发语言中使用;(C#,java,JS,PHP等)
- 网络爬虫;
- 批量文本处理等;
- xcode中快使用
2.2 语法
2.2.1 元字符
| 元字符 | 描述 | |
|---|---|---|
| . | 句号匹配任意单个字符除了换行符. | |
| [ ] | 字符种类. 匹配方括号内的任意字符. | |
| [^ ] | 否定的字符种类. 匹配除了方括号里的任意字符 | |
| * | 匹配>=0个重复的在*号之前的字符. | |
| + | 匹配>=1个重复的+号前的字符. | |
| ? | 标记?之前的字符为可选. | |
| {n,m} | 匹配num个大括号之前的字符 (n <= num <= m). | |
| (xyz) | 字符集, 匹配与 xyz 完全相等的字符串. | |
| | | 或运算符,匹配符号前或后的字符. | |
| \ | 转义字符,用于匹配一些保留的字符 `[ ] ( ) { } . * + ? ^ $ \ | ` |
| 从开始行开始匹配. | ||
| $ | 从末端开始匹配. |
2.2.2 简写字符集
| 简写 | 描述 |
|---|---|
| . | 除换行符外的所有字符 |
| \w | 匹配所有字母数字, 等同于 [a-zA-Z0-9_] |
| \W | 匹配所有非字母数字, 即符号, 等同于: [^\w] |
| \d | 匹配数字: [0-9] |
| \D | 匹配非数字: [^\d] |
| \s | 匹配所有空格字符, 等同于: [\t\n\f\r\p{Z}] |
| \S | 匹配所有非空格字符: [^\s] |
| \f | 匹配一个换页符 |
| \n | 匹配一个换行符 |
| \r | 匹配一个回车符 |
| \t | 匹配一个制表符 |
| \v | 匹配一个垂直制表符 |
| \p | 匹配 CR/LF (等同于 \r\n),用来匹配 DOS 行终止符 |
2.2.3 零宽度断言(前后预查)
先行断言和后发断言都属于非捕获簇(不捕获文本 ,也不针对组合计进行计数). 先行断言用于判断所匹配的格式是否在另一个确定的格式之前, 匹配结果不包含该确定格式(仅作为约束).
例如, 我们想要获得所有跟在 $ 符号后的数字, 我们可以使用正后发断言 (?<=\$)[0-9\.]*. 这个表达式匹配 $ 开头, 之后跟着 0,1,2,3,4,5,6,7,8,9,. 这些字符可以出现大于等于 0 次.
零宽度断言如下:
| 符号 | 描述 |
|---|---|
| ?= | 正先行断言-存在 |
| ?! | 负先行断言-排除 |
| ?<= | 正后发断言-存在 |
| ?<! | 负后发断言-排除 |
2.2.4 标志
标志也叫模式修正符, 因为它可以用来修改表达式的搜索结果. 这些标志可以任意的组合使用, 它也是整个正则表达式的一部分.
| 标志 | 描述 |
|---|---|
| i | 忽略大小写. |
| g | 全局搜索. |
| m | 多行的: 锚点元字符 ^ $ 工作范围在每行的起始. |
2.2.5 优先级
在这些运算符同时出现时,按照下面的优先级进行操作。
| 优先级 | 符号 |
|---|---|
| 最高 | \ |
| 高 | ( )、(?: )、(?= )、[ ] |
| 中 | *、+、?、{n}、{n,}、{n,m} |
| 低 | ^、$、中介字符 |
| 最低 | | |
2.2.6 贪婪匹配与惰性匹配
正则表达式默认采用贪婪匹配模式,在该模式下意味着会匹配尽可能长的子串。我们可以使用 ? 将贪婪匹配模式转化为惰性匹配模式。
贪婪模式
(.*nt)=>People want to try something different.
惰性模式
(.*?nt)=>People wantto try something different.
常见的惰性限定符:
| 符号 | 说明 |
|---|---|
| *? | 重复任意次,但尽可能少重复 |
| +? | 重复1次或更多次,但尽可能少重复 |
| ?? | 重复0次或1次,但尽可能少重复 |
| {n,m}? | 重复n到m次,但尽可能少重复 |
| {n,}? | 重复n次以上,但尽可能少重复 |
三. iOS中的应用
3.1 NSPredicate
3.1.1 概念
谓词:一种逻辑条件的定义,用于约束查找或者内存中筛选的搜索条件,一个用来匹配查询结果的条件,类似于SQL中的where语句.
3.1.2 API
// 通过表达式创建谓词实例
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;
// 表达式中的%@从arguments中取值
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat argumentArray:(nullable NSArray *)arguments;
// 表达式中的%@占位符将从argList中取值
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat arguments:(va_list)argList;
// 通过一个元数据查询字符串来创建谓词实例,仅macos可以使用
+ (nullable NSPredicate *)predicateFromMetadataQueryString:(NSString *)queryString API_AVAILABLE(macos(10.9)) API_UNAVAILABLE(ios, watchos, tvos);
// 创建一个固定结果为BOOL值的谓词实例
+ (NSPredicate *)predicateWithValue:(BOOL)value;
// 根据block的回调的返回值创建一个结果为YES/NO的谓词实例
+ (NSPredicate*)predicateWithBlock:(BOOL (^)(id _Nullable evaluatedObject, NSDictionary<NSString *, id> * _Nullable bindings))block API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
// 获取谓词的表达式,只读属性
@property (readonly, copy) NSString *predicateFormat;
// 用常量值代替变量,用字典中的键值对替换用$声明的变量
- (instancetype)predicateWithSubstitutionVariables:(NSDictionary<NSString *, id> *)variables; // substitute constant values for variables
// 比较评估对象是否符合谓词
- (BOOL)evaluateWithObject:(nullable id)object;
// 比较评估对象是否符合谓词
- (BOOL)evaluateWithObject:(nullable id)object substitutionVariables:(nullable NSDictionary<NSString *, id> *)bindings API_AVAILABLE(macos(10.5), ios(3.0), watchos(2.0), tvos(9.0));
// 强制使用已安全解码的谓词以进行评估
- (void)allowEvaluation API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));
3.1.3 常用方法
// 创建谓词
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"SELF CONTAINS 'world'"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"SELF CONTAINS %@", @"world"];
NSPredicate *predicate3 = [NSPredicate predicateWithFormat:@"SELF CONTAINS %@" argumentArray:@[@"world"]];
NSLog(@"predicate1谓词表达式:%@", predicate1.predicateFormat);
NSLog(@"predicate2谓词表达式:%@", predicate2.predicateFormat);
NSLog(@"predicate3谓词表达式:%@", predicate3.predicateFormat);
// 使用
NSString *str = @"Hello, world";
NSLog(@"谓词评估结果:%hhd",[predicate1 evaluateWithObject:str]); // 打印 谓词评估结果:1
NSString *regex = @"^[0-9]+$";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
NSString *str = @"1314";
if ([predicate evaluateWithObject:str]) {
NSLog(@"Condition Matched");
}
3.2 NSString
只能匹配第一个,可指定是否区分大小写,可用于替换字符串
NSString *searchText = @"targetString";
NSRange range = [searchText rangeOfString:@"^[0-9]+$" options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
NSLog(@"target range :%@", [searchText substringWithRange:range]);
}
3.3 NSRegularExpression
/*
typedef NS_OPTIONS(NSUInteger, NSRegularExpressionOptions) {
NSRegularExpressionCaseInsensitive = 1 << 0, //不区分字母大小写的模式
NSRegularExpressionAllowCommentsAndWhitespace = 1 << 1, //忽略掉正则表达式中的空格和#号之后的字符
NSRegularExpressionIgnoreMetacharacters = 1 << 2, //将正则表达式整体作为字符串处理
NSRegularExpressionDotMatchesLineSeparators = 1 << 3, //允许.匹配任何字符,包括换行符
NSRegularExpressionAnchorsMatchLines = 1 << 4, //允许^和$符号匹配行的开头和结尾
NSRegularExpressionUseUnixLineSeparators = 1 << 5, //设置\n为唯一的行分隔符,否则所有的都有效。
NSRegularExpressionUseUnicodeWordBoundaries = 1 << 6 //使用Unicode TR#29标准作为词的边界,否则所有传统正则表达式的词边界都有效
};
*/
NSString *searchText = @"what do you want to match string";
NSError *error = NULL;
// 创建一个正则
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]+$" options:NSRegularExpressionCaseInsensitive error:&error];
/********************** 匹配方法 ************************/
//仅取出第一条匹配记录
NSTextCheckingResult *firstResult = [regex firstMatchInString:searchText options:0 range:NSMakeRange(0, [searchText length])];
if (firstResult) {
NSLog(@"firstResult:%@", [searchText substringWithRange:firstResult.range]);
}
//遍历所有匹配记录
NSArray *matches = [regex matchesInString:searchText
options:0
range:NSMakeRange(0, searchText.length)];
for (NSTextCheckingResult *match in matches) {
NSRange range = [match range];
NSString *mStr = [searchText substringWithRange:range];
NSLog(@"AllResult:%@", mStr);
}
// 返回匹配总数
NSUInteger count = [regex numberOfMatchesInString:searchText option:0 range:NSMakeRange(0,searchText.length)];
/********************** 替换方法 ************************/
// 返回替换后的新字符串, 源字符串不变
NSString *newString = [regex stringByReplacingMatchesInString:searchText options:0 range:NSMakeRange(0,searchText.length) withTemplate:@"11"];
// 直接在源字符串里替换
[regex replaceMatchesInString:searchText options:0 range:NSMakeRange(0,searchText.length) withTemplate:@"111"];