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
- 说明1
若不想指定选项,可以传入0
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
- 说明2
若不想指定,则传入0,此时只有成功匹配时才会回调。
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
};
- 说明3
typedef NS_OPTIONS(NSUInteger, NSMatchingFlags) {
//还在长时间的匹配中
NSMatchingProgress = 1 << 0,
//匹配已经完成
NSMatchingCompleted = 1 << 1,
//当前匹配操作到达搜索范围的末尾
NSMatchingHitEnd = 1 << 2,
//当前匹配项取决于搜索范围末端的位置
NSMatchingRequiredEnd = 1 << 3,
//由于内部错误而导致匹配失败而没有检查整个搜索范围
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]);
}
//相当于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
- 例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替换匹配的字符串 返回替换的数量
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];
//因为替换字符串的长度与原字符串不一致 需要设置偏移量
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) {
//系统保留前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}"
)
匹配出两个字符串,一个是链接,一个是号码。